// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: N2_Core.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 "BL_BitUtility.h"
N2_Core::N2_Core( N2_Cpu
& _cpu
, const char* _name
, uint_t strand_id_base
)/*{{{*/
inst_tlb(SS_Tlb::INST_TLB
,N2_Tlb::ITLB_SIZE
),
data_tlb(SS_Tlb::DATA_TLB
,N2_Tlb::DTLB_SIZE
),
for (uint_t i
=0; i
< N2_Model::NO_STRANDS_PER_CORE
; i
++)
void* s
= ss_memalign(64,sizeof(N2_Strand
));
new(s
) N2_Strand(*this,num
,strand_id_base
+ i
);
strand
[i
] = (N2_Strand
*)s
;
asi_map
[0x42].add(0x08,0x08,this,0,
inst_iw_ld64
,inst_iw_st64
,
inst_iw_ld64
,inst_iw_st64
);
asi_map
[0x42].add(0x10,this,lsu_diag
);
asi_map
[0x43].add(0x00,this,&error_inject
,
SS_SharedAsiCtrReg::ld64
,error_inject_st64
,
SS_SharedAsiCtrReg::rd64
,error_inject_st64
);
asi_map
[0x45].add(0x08,this,decr
);
asi_map
[0x46].set_mask(N2_DcacheDataStReg::DCACHE_DATA_SIZE_MASK
);
asi_map
[0x46].add(SS_VADDR_MIN
,SS_VADDR_MAX
,this,0,
dcache_data_ld64
,dcache_data_st64
,
dcache_data_ld64
,dcache_data_st64
);
asi_map
[0x47].set_mask(N2_DcacheTagLdReg::DCACHE_TAG_SIZE_MASK
);
asi_map
[0x47].add(0x0,(N2_DcacheTagLdReg::DCACHE_TAG_SIZE_MASK
-1),this,0,
dcache_tag_ld64
,dcache_tag_st64
,
dcache_tag_ld64
,dcache_tag_st64
);
asi_map
[0x4c].add(0x08,this,&dfesr
,
SS_SharedAsiCtrReg::ld64
,0,
SS_SharedAsiCtrReg::rd64
,SS_SharedAsiCtrReg::wr64
);
asi_map
[0x4c].add(0x10,this,cerer
);
asi_map
[0x4c].add(0x20,this,&clesr
,
SS_SharedAsiCtrReg::ld64
,0,
SS_SharedAsiCtrReg::rd64
,0);
asi_map
[0x4c].add(0x28,this,&clfesr
,
SS_SharedAsiCtrReg::ld64
,0,
SS_SharedAsiCtrReg::rd64
,0);
asi_map
[0x4e].add(0x00,this,power_mgmt
);
asi_map
[0x50].add(0x38,0x38,this,0,
inst_wp_ld64
,inst_wp_st64
,
inst_wp_ld64
,inst_wp_st64
);
asi_map
[0x54].add(0x98,this,&tw_status
,
tw_status_ld64
,SS_SharedAsiCtrReg::wr64
);
asi_map
[0x66].set_mask(N2_IcacheInstrStReg::ICACHE_DATA_SIZE_MASK
);
asi_map
[0x66].add(0x0,(N2_IcacheInstrStReg::ICACHE_DATA_SIZE_MASK
-1),this,0,
icache_data_ld64
,icache_data_st64
,
icache_data_ld64
,icache_data_st64
);
asi_map
[0x67].set_mask(N2_IcacheTagLdReg::ICACHE_TAG_SIZE_MASK
);
asi_map
[0x67].add(0x0,(N2_IcacheTagLdReg::ICACHE_TAG_SIZE_MASK
-1),this,0,
icache_tag_ld64
,icache_tag_st64
,
icache_tag_ld64
,icache_tag_st64
);
N2_Core::~N2_Core()/*{{{*/
void N2_Core::hard_reset()/*{{{*/
for (uint s
=0; s
< N2_Model::NO_STRANDS_PER_CORE
; s
++)
((N2_Strand
*)strand
[s
])->hard_reset();
void N2_Core::warm_reset(bool intp
)/*{{{*/
for (uint s
=0; s
< N2_Model::NO_STRANDS_PER_CORE
; s
++)
((N2_Strand
*)strand
[s
])->warm_reset(intp
);
void N2_Core::snapshot( SS_SnapShot
& ss
)/*{{{*/
power_mgmt
.snapshot(ss
,prefix
);
error_inject
.snapshot(ss
,prefix
);
decr
.snapshot(ss
,prefix
);
dfesr
.snapshot(ss
,prefix
);
cerer
.snapshot(ss
,prefix
);
clesr
.snapshot(ss
,prefix
);
clfesr
.snapshot(ss
,prefix
);
SS_SharedAsiCtrReg::snapshot(ss
,inst_iw
,2,prefix
);
SS_SharedAsiCtrReg::snapshot(ss
,inst_wp
,2,prefix
);
lsu_diag
.snapshot(ss
,prefix
);
for (int s
=0; s
< N2_Model::NO_STRANDS_PER_CORE
; s
++)
inst_tlb
.snapshot(ss
,prefix
,"inst");
data_tlb
.snapshot(ss
,prefix
,"data");
// Deal with loaded values that need to propagate through the
// model into the strands etc.
// Deal with values that have sife effecrts when written to.
// This to ensure everything is updated. We reuse thet asi st64
// functions for this and pass sensible values for unused parameters.
inst_iw_st64(this,0,strand
[0],0,inst_iw
[0]());
inst_iw_st64(this,0,strand
[2],0,inst_iw
[1]());
inst_wp_st64(this,0,strand
[0],0,inst_wp
[0]());
inst_wp_st64(this,0,strand
[2],0,inst_wp
[1]());
void N2_Core::ras_enable(char*)/*{{{*/
for (int s
=0; s
< N2_Model::NO_STRANDS_PER_CORE
; s
++)
strand
[s
]->ras_enable(strand
[s
], NULL
);
SS_AsiSpace::Error
N2_Core::inst_iw_ld64( SS_Node
* _core
, void*, SS_Strand
* s
, SS_Vaddr va
, uint64_t* data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
N2_InstMask
* r
= &core
->inst_iw
[(s
->strand_id() >> 2) & 1];
SS_AsiSpace::Error
N2_Core::inst_iw_st64( SS_Node
* _core
, void*, SS_Strand
* s
, SS_Vaddr va
, uint64_t data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
uint_t i
= s
->strand_id() & 4;
N2_InstMask
* r
= &core
->inst_iw
[i
>> 2];
if (r
->en_rs2()) iw_mask
|= 0x1f;
if (r
->en_asi()) iw_mask
|= 0xff << 5;
if (r
->en_i()) iw_mask
|= 0x01 << 13;
if (r
->en_rs1()) iw_mask
|= 0x1f << 14;
if (r
->en_op3()) iw_mask
|= 0x3f << 19;
if (r
->en_rd()) iw_mask
|= 0x1f << 25;
if (r
->en_op()) iw_mask
|= 0x03 << 30;
uint32_t iw_data
= r
->iw() & iw_mask
;
core
->strand
[i
]->inst_breakpoint_set(0,iw_mask
,iw_data
);
core
->strand
[i
+ 1]->inst_breakpoint_set(0,iw_mask
,iw_data
);
core
->strand
[i
+ 2]->inst_breakpoint_set(0,iw_mask
,iw_data
);
core
->strand
[i
+ 3]->inst_breakpoint_set(0,iw_mask
,iw_data
);
SS_AsiSpace::Error
N2_Core::inst_wp_ld64( SS_Node
* _core
, void*, SS_Strand
* s
, SS_Vaddr va
, uint64_t* data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
uint_t i
= s
->strand_id() & 4;
N2_InstWp
* r
= &core
->inst_wp
[i
>> 2];
*data
= r
->get(); // Signextended on store
SS_AsiSpace::Error
N2_Core::inst_wp_st64( SS_Node
* _core
, void*, SS_Strand
* s
, SS_Vaddr va
, uint64_t data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
uint_t i
= s
->strand_id() & 4;
N2_InstWp
* r
= &core
->inst_wp
[i
>> 2];
uint64_t old_enabled
= r
->enabled();
// Sign extend from bit47 up now which saves a shift later in use :-)
// but first clip of the bits that are RO.
r
->set_unmasked((SS_Vaddr(r
->get()) << (64 - s
->va_bits())) >> (64 - s
->va_bits()));
// Bit0 of the address is used to indicate enabled (0) or disabled (1)
// This saves an extra compare, eg. bit 0 of the PC is always 0
// so a disabled watchpoint has the address bit0 set, so addr won't
// compare equal to the PC when disabled - ever.
SS_Vaddr addr
= (r
->va() << 2) + !r
->enabled();
SS_Vaddr mask
= (SS_Vaddr(1) << 48) - 4;
core
->strand
[i
]->inst_watchpoint_va_set(mask
,addr
);
core
->strand
[i
+ 1]->inst_watchpoint_va_set(mask
,addr
);
core
->strand
[i
+ 2]->inst_watchpoint_va_set(mask
,addr
);
core
->strand
[i
+ 3]->inst_watchpoint_va_set(mask
,addr
);
// On every watchpoint change we signal flush decode caches to
// all strands ... as we use the decode cache to store special
// decoders that have knowledge about the watchpoints.
sgn
= s
->msg
.make_signal(SS_Signal::FLUSH_VA
);
core
->strand
[i
]->post_signal(sgn
);
sgn
= s
->msg
.make_signal(SS_Signal::FLUSH_VA
);
core
->strand
[i
+ 1]->post_signal(sgn
);
sgn
= s
->msg
.make_signal(SS_Signal::FLUSH_VA
);
core
->strand
[i
+ 2]->post_signal(sgn
);
sgn
= s
->msg
.make_signal(SS_Signal::FLUSH_VA
);
core
->strand
[i
+ 3]->post_signal(sgn
);
SS_AsiSpace::Error
N2_Core::icache_tag_ld64( SS_Node
* _core
, void*, SS_Strand
* s
, SS_Vaddr va
, uint64_t* data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
// convert ASI_VA to hardware index/way
N2_IcacheDiagTagAddrFields diagTagAddr
;
diagTagAddr
.perren(0);// clear the err inject and valid bits
diagTagAddr
.vb_err_en(0); // before accessing the ASI map
*data
= (core
->icacheTag
.get(diagTagAddr
))();
SS_AsiSpace::Error
N2_Core::icache_tag_st64( SS_Node
* _core
, void*, SS_Strand
*, SS_Vaddr va
, uint64_t data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
// ASI VA for tag contains, way/index,
// parity error enable and vb_err_enable
N2_IcacheDiagTagAddrFields vaddr
;
N2_IcacheDiagTagAddrFields indexVa
= vaddr
;
indexVa
.perren(0); // clear the err inject and valid bits
indexVa
.vb_err_en(0); // before accessing the ASI map
N2_IcacheTagLdReg icacheTagLdReg
;
icacheTagLdReg
.set(data
);
// calculate parity over tag
uint64_t t
= BL_BitUtility::calc_parity(icacheTagLdReg
.tag());
t
^= vaddr
.perren(); // invert parity if perren is one
icacheTagLdReg
.tag_parity(t
);
// enforce valid bit error injection enable
icacheTagLdReg
.valid0(icacheTagLdReg
.valid1() ^ vaddr
.vb_err_en());
// write the tag back into the cache
core
->icacheTag
.set(indexVa
, icacheTagLdReg
);
/* Flush all the decode caches associated with this core */
SS_AsiSpace::Error
N2_Core::icache_data_ld64( SS_Node
* _core
, void*, SS_Strand
* s
, SS_Vaddr va
, uint64_t* data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
// convert ASI_VA to hardware index/way
N2_IcacheDiagInstrAddrFields diagInstrAddr
;
uint64_t index
= diagInstrAddr();
*data
= core
->icacheInstr
[index
]();
SS_AsiSpace::Error
N2_Core::icache_data_st64( SS_Node
* _core
, void*, SS_Strand
*, SS_Vaddr va
, uint64_t data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
// extract icache perrinj, way, and index from ASI_VA
N2_IcacheDiagInstrAddrFields vaddr
;
uint64_t index
= vaddr();
N2_IcacheInstrStReg icacheInstrStReg
;
icacheInstrStReg
.set(data
);
uint32_t t
= BL_BitUtility::calc_parity(icacheInstrStReg
.instr());
t
^= icacheInstrStReg
.perrinj();
// merge parity into data
icacheInstrStReg
.perrinj(t
);
// write the data (instr) into the I-cache
core
->icacheInstr
[index
] = icacheInstrStReg
;
SS_AsiSpace::Error
N2_Core::dcache_tag_ld64( SS_Node
* _core
, void*, SS_Strand
* s
, SS_Vaddr va
, uint64_t* data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
N2_DcacheDiagTagAddrFields dcacheDiagTagAddr
;
dcacheDiagTagAddr
.set(va
);
*data
= (core
->dcacheTag
[dcacheDiagTagAddr()])();
SS_AsiSpace::Error
N2_Core::dcache_tag_st64( SS_Node
* _core
, void*, SS_Strand
*, SS_Vaddr va
, uint64_t data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
// ASI_VA contains valid bit error enable (vb_err_en)
// parity error enable (perren)
// way and index (way_index)
N2_DcacheDiagTagAddrFields vaddr
;
uint64_t vb_err_en
= vaddr
.vb_err_en();
uint64_t perren
= vaddr
.perren();
// clear out reserved bits from the data
N2_DcacheTagLdReg dcacheTagLdReg
;
dcacheTagLdReg
.set(data
);
// calculate parity over tag and tag valid
parity
= BL_BitUtility::calc_parity(dcacheTagLdReg
.tag());
// merge parity and valid bits
dcacheTagLdReg
.tag_parity(parity
);
dcacheTagLdReg
.valid0(dcacheTagLdReg
.valid1() ^ vb_err_en
);
// write it into the D$ tag
core
->dcacheTag
[vaddr()].set(dcacheTagLdReg());
SS_AsiSpace::Error
N2_Core::dcache_data_ld64( SS_Node
* _core
, void*, SS_Strand
* s
, SS_Vaddr va
, uint64_t* data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
N2_DcacheDiagDataLdAddrFields dcacheDiagDataLdAddr
;
dcacheDiagDataLdAddr
.set(va
);
*data
= (core
->dcacheData
[dcacheDiagDataLdAddr()])();
SS_AsiSpace::Error
N2_Core::dcache_data_st64( SS_Node
* _core
, void*, SS_Strand
*, SS_Vaddr va
, uint64_t data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
// ASI VA contains D$ index, and parity error injection mask
N2_DcacheDiagDataStAddrFields vaddr
;
uint64_t index
= vaddr
.index();
uint64_t perrmask
= vaddr
.perrmask();
parity
= BL_BitUtility::calc_byte_parities(data
);
// This ends up being a write to data *and* parity
N2_DcacheDiagDataLdAddrFields ldVa
;
// Write the parity into the cache
core
->dcacheData
[ldVa()].set(parity
);
core
->dcacheData
[ldVa()].set(data
);
SS_AsiSpace::Error
N2_Core::tw_status_ld64( SS_Node
* _core
, void*, SS_Strand
* s
, SS_Vaddr va
, uint64_t* data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
for (uint_t i
=0; i
< N2_Model::NO_STRANDS_PER_CORE
; i
++)
tws
|= core
->strand
[i
]->tw_status
<< i
;
core
->tw_status
.htp(tws
);
*data
= core
->tw_status();
core
->tw_status
.unlock();
SS_AsiSpace::Error
N2_Core::error_inject_st64( SS_Node
* _core
, void* _reg
, SS_Strand
* , SS_Vaddr
, uint64_t data
)/*{{{*/
N2_Core
* core
= (N2_Core
*)_core
;
N2_ErrorInject
* reg
= (N2_ErrorInject
*) _reg
;
/* If IRF/FRF injection is set , then enable the inject/detect in RAS mode */
/* for performance reasons these are not enabled immediately while transitioning to RAS mode */
for (uint_t ndx
= 0; ndx
< N2_Model::NO_STRANDS_PER_CORE
; ++ndx
)
N2_Strand
* s
= core
->strand
[ndx
];
if(s
->sim_state
.ras_enabled())
s
->ras_rs1
= n2_irf_ras_detect
;
s
->ras_rs2
= n2_irf_ras_detect
;
s
->ras_rs3
= n2_irf_ras_detect
;
s
->ras_rd
= n2_irf_ras_inject
;
for (uint_t ndx
= 0; ndx
< N2_Model::NO_STRANDS_PER_CORE
; ++ndx
)
N2_Strand
* s
= core
->strand
[ndx
];
if(s
->sim_state
.ras_enabled())
s
->ras_frs1
= n2_frf_ras_detect
;
s
->ras_frs2
= n2_frf_ras_detect
;
s
->ras_frs3
= n2_frf_ras_detect
;
s
->ras_frd
= n2_frf_ras_inject
;
s
->ras_drs1
= n2_frf_dp_ras_detect
;
s
->ras_drs2
= n2_frf_dp_ras_detect
;
s
->ras_drs3
= n2_frf_dp_ras_detect
;
s
->ras_drd
= n2_frf_dp_ras_inject
;
void N2_Core::update_clesr(int sid
, int isDesr
, uint64_t value
)/*{{{*/
// 'value' is either desr or dfesr's F field, record it in clesr's
// corresponding bit location
int shift
= 48 + (sid
* 2) + isDesr
;
uint64_t mask
= 1 << shift
;
uint64_t data
= value
<< shift
;
uint64_t origData
= clesr
.get();
uint64_t newData
= (origData
& ~mask
) | data
;
if ((clfesr
.get() & mask
) == 0)
// the corresponding bit in clfesr is not set, record the new value
newData
= (origData
& ~mask
) | data
;
else if (clesr
.get() == 0)
// clesr is clear, so go ahead and clear clfesr
SS_Trap::Type
N2_Core::icache_ifetch(
const MemoryTransaction
&memXact
,
N2_MemErrDetector
*mem_err_detector
)/*{{{*/
/***************************************************
* Adding I-cache RAS error check here inline, because
* I'm not quite sure where else to add it
* The map icacheTag_ contains all the tags for this
* The map icacheData_ contains all the data for this
* 1. Search for tag valid errors
* trap_type = HW_CORRECTED_ERROR
* 2. Search for tag parity errors
* trap_type = HW_CORRECTED_ERROR
* 3. Search for hit and multi-hit errors
* trap_type = HW_CORRECTED_ERROR
* if instruction parity error
* trap_type = HW_CORRECTED_ERROR
* 5. if line not in cache
* pick and allocate L1 way
* set good tag parity/valid
***************************************************/
// Split physical address into icache index and tag
N2_IcacheAddressingFields pc_pa
;
pc_pa
.set(memXact
.getPaddr());
uint64_t index
= pc_pa
.sets(); // Tbl B-2 refers to SET
// Tbl 28-8 and -10 to index
uint64_t tag
= pc_pa
.tag();
N2_Desr
&desr
= strand
[strand_id
]->desr
;
icache_empty
= false; // remember the I$ has been used
uint32_t errortype
= search_icache_tags(pc_pa
, hit_way
);
// if there were no errors and we got a hit, then lets check the
// addressed instruction for parity error
if (errortype
== 0 && hit_way
!= -1)
N2_IcacheDiagInstrAddrFields diagInstrAddr
;
diagInstrAddr
.index(index
);
diagInstrAddr
.word(pc_pa
.instr()); // WORD == INSTR in PRM
N2_IcacheInstrStReg icacheInstrStReg
= icacheInstr
[diagInstrAddr()];
uint32_t pe
= icacheInstrStReg
.instr(); // extract instruction
// calculate parity over instruction
pe
= BL_BitUtility::calc_parity(pe
);
pe
^= icacheInstrStReg
.perrinj(); // xor in parity bit
// if this comes up one then we have a parity error
// all done checking for errors
// no errors. If we got a miss (no tag match), then create a new
// line in the cache (possibly overwriting a currently valid entry)
// we didn't get a tag match
//TODO: Handle NotData poison here.
SS_Trap::Type trapNumber
= SS_Trap::NO_TRAP
;
trapNumber
= mem_err_detector
->L2CacheFill(memXact
);
// For now, just create a clean line with valid tag
uint32_t way
= (icache_lru
++ % N2_IcacheAddressingFields::ICACHE_WAYS
);
N2_IcacheDiagInstrAddrFields diagInstrAddr
;
diagInstrAddr
.index(index
);
// Clean out any old errors
for (int word
= 0; word
< 8; word
++)
diagInstrAddr
.word(word
);
icacheInstr
.erase(diagInstrAddr());
if (trapNumber
!= SS_Trap::NO_TRAP
)
N2_IcacheInstrStReg
&icacheInstrStReg
= icacheInstr
[diagInstrAddr()];
icacheInstrStReg
.perrinj(1);
int64_t tag_pe
= BL_BitUtility::calc_parity(tag
);
// format tag entry in ASI format
N2_IcacheDiagTagAddrFields diagTagAddr
;
diagTagAddr
.index(index
);
// write the tag into the cache
icacheTag
.set(diagTagAddr
, obj
);
if (trapNumber
!= SS_Trap::NO_TRAP
)
// Now poison all matching decode cache entries
strand
[strand_id
]->flush(pc_pa(), true);
// we detected some kind of error (recorded in errortype)
// we try to record into Disrupting Error Status Register (DESR)
{ // record the error address if not full
desr
.erraddr((hit_way
<< 6) | (pc_pa
.sets()));
// hardware automatically recovers from this error by erasing
for (uint32_t way
= 0; way
< N2_IcacheAddressingFields::ICACHE_WAYS
; way
++)
N2_IcacheDiagTagAddrFields diagTagAddr
;
diagTagAddr
.index(index
);
N2_IcacheTagLdReg tagReg
= icacheTag
.get(diagTagAddr
);
icacheTag
.set(diagTagAddr
, tagReg
);
N2_IcacheDiagInstrAddrFields diagInstrAddr
;
diagInstrAddr
.index(index
);
for (int word
= 0; word
< 8; word
++)
diagInstrAddr
.word(word
);
icacheInstr
.erase(diagInstrAddr());
// if DESR not full, record error type, and mark it full
// FIXME: set the CLESR.T field for this strand
// if DESR was already full, indicate multiple error
update_clesr(strand_id
, 1, desr
.f());
return SS_Trap::HW_CORRECTED_ERROR
;
// flushIcache() flushes the I-cache line at paddr.
// No RAS correction or detection occurs.
void N2_Core::flush_icache(uint64_t paddr
)/*{{{*/
if (icache_empty
) // avoid searching I$ if empty
N2_IcacheAddressingFields pc_pa
;
// Verify correct alignment
(N2_IcacheAddressingFields::WIDTH_RSVD0
+
N2_IcacheAddressingFields::WIDTH_INSTR
))) {
fprintf(stderr
, "Internal error: N2_core::flushIcache(): "
"misaligned paddr 0x%ullx", paddr
);
// Look for a matching line in the cache and invalidate it
search_icache_tags(pc_pa
, hit_way
);
N2_IcacheTagLdReg icacheTagLdReg
;
icacheTagLdReg
.valid1(0);
icacheTagLdReg
.valid0(0);
N2_IcacheDiagTagAddrFields diagTagAddr
;
diagTagAddr
.index(pc_pa
.sets());
diagTagAddr
.way(hit_way
);
// write the tag into the cache
icacheTag
.set(diagTagAddr
, icacheTagLdReg
);
// searchIcacheTags() returns the RAS error type found in Tbl. 12-13,
// N2 1.1 PRM. It is passed the physical address to be looked up and
// a reference to the matching way if the address hits in the I-cache.
// If there is no hit, the reference is set to -1.
// A subset of the physical address, called index, gets us down to a
// set of 8 places where our instructions might be. A given entry in
// our set of 8 is called a way.
// room for 8 instructions (32 bytes aligned on 32 byte boundary)
// valid bit(s) so we know if the instructions are meaningful
// tag - the bits of the physical address not used as index or to
// address individual instructions
// each instruction has a parity bit (even parity)
// tag valid is duplicated (parity)
// tag has parity (even parity)
uint32_t N2_Core::search_icache_tags(N2_IcacheAddressingFields paddr
,int32_t &hit_way
)/*{{{*/
uint64_t index
= paddr
.sets(); // Tbl B-2 refers to SET
// Tbl 28-8 and -10 to index
uint64_t tag
= paddr
.tag();
char valids
[N2_IcacheAddressingFields::ICACHE_WAYS
];
char perrs
[N2_IcacheAddressingFields::ICACHE_WAYS
];
uint64_t tags
[N2_IcacheAddressingFields::ICACHE_WAYS
];
// walk through the tag array finding out which tags are valid
// and checking for tag valid errors
for (way
= 0; way
< N2_IcacheAddressingFields::ICACHE_WAYS
; way
++)
N2_IcacheDiagTagAddrFields diagTagAddr
;
diagTagAddr
.index(index
);
// use way and index to look up tags in map
N2_IcacheTagLdReg icacheTagLdReg
= icacheTag
.get(diagTagAddr
);
// tag found in map (may have valids == 0)
valids
[way
] = (icacheTagLdReg
.valid1() << 1) | icacheTagLdReg
.valid0();
// check valids (Should be the same, so 0 and 3 are good, 1 and 2 bad)
if (valids
[way
] == 1 || valids
[way
] == 2)
if (cerer
.icvp()) { // I-cache Valid Parity Error
// extract the tag (address bits)
tags
[way
] = icacheTagLdReg
.tag();
// calculate tag parity using log2 N based XOR trick
pe
= BL_BitUtility::calc_parity(tags
[way
]);
pe
^= icacheTagLdReg
.tag_parity();
// if there were no tag valid errors, check for tag parity errors
for (way
= 0; way
< N2_IcacheAddressingFields::ICACHE_WAYS
; way
++)
if (valids
[way
] && perrs
[way
] && cerer
.ictp())
// we got valid tag, with errors and we're enabled for
// if there were no tag parity errors, look for tag matching the
// requesting physical address. If there is more than one tag
// match try to report tag multi-hit error (if CERER allows)
for (way
= 0; way
< N2_IcacheAddressingFields::ICACHE_WAYS
; way
++)
if (valids
[way
] && tag
== tags
[way
])
// if we already had tag hit, and CERER allows report
// remember that we got a tag match, and remember the way
SS_Trap::Type
N2_Core::dcache_trans( const MemoryTransaction
&memXact
,
N2_MemErrDetector
*mem_err_detector
)/*{{{*/
/***************************************************
* The map dcacheTag_ contains all the tags for this
* The map dcacheData_ contains all the data and
* 1. Search for tag valid errors
* trap_type = HW_CORRECTED_ERROR
* 2. Search for tag parity errors
* trap_type = HW_CORRECTED_ERROR
* 3. Search for hit and multi-hit errors
* trap_type = HW_CORRECTED_ERROR
* if instruction parity error
* trap_type = HW_CORRECTED_ERROR
* 5. if line not in cache
* pick and allocate L1 way
* set good tag parity/valid
***************************************************/
N2_Desr
&desr
= strand
[strand_id
]->desr
;
N2_DcacheAddressingFields paddr
;
paddr
.set(memXact
.getPaddr());
uint64_t index
= paddr
.sets();
uint64_t tag
= paddr
.tag();
uint64_t dw
= paddr
.data();
dcache_empty
= false; // remember the D$ has been used
uint32_t errortype
= search_dcache_tags(paddr
, hit_way
);
// we found a tag match (hit) so check data parity
N2_DcacheDiagDataLdAddrFields dcacheDiagDataLdAddr
;
dcacheDiagDataLdAddr
.way(way
);
dcacheDiagDataLdAddr
.index(index
);
dcacheDiagDataLdAddr
.doubleword(dw
);
N2_DcacheDataStReg dcacheDataStReg
= dcacheData
[dcacheDiagDataLdAddr()];
uint64_t parity
= dcacheDataStReg
.data();
if (calc_dcache_parity(dcacheDiagDataLdAddr
) != parity
&& memXact
.readXact())
// writes update the dirty bits in the L2$
if (memXact
.writeXact()/* || memXact.rdwrXact()*/)
SS_Trap::Type tt
= strand
[strand_id
]->fill_store_buffer_mem(memXact
);
if(tt
!= SS_Trap::NO_TRAP
)
SS_Trap::Type tt
= mem_err_detector
->L2CacheFill(memXact
);
if(tt
!= SS_Trap::NO_TRAP
)
// Create a clean line with valid tag
uint32_t way
= (dcache_lru
++ % N2_DcacheAddressingFields::DCACHE_WAYS
);
N2_DcacheDiagDataLdAddrFields dcacheDiagDataLdAddr
;
dcacheDiagDataLdAddr
.way(way
);
dcacheDiagDataLdAddr
.index(index
);
for (int dword
= 0; dword
< (1<<N2_DcacheDiagDataLdAddrFields::bit_size_doubleword
); dword
++)
dcacheDiagDataLdAddr
.doubleword(dw
);
dcacheData
.erase(dcacheDiagDataLdAddr());
dcacheDiagDataLdAddr
.data_notparity(1);
dcacheData
.erase(dcacheDiagDataLdAddr());
dcacheDiagDataLdAddr
.data_notparity(0);
int64_t tag_pe
= BL_BitUtility::calc_parity(tag
);
N2_DcacheDiagTagAddrFields dcacheDiagTagAddr
;
dcacheDiagTagAddr
.way(way
);
dcacheDiagTagAddr
.index(index
);
N2_DcacheTagLdReg dcacheTagLdReg
;
dcacheTagLdReg
.tag_parity(tag_pe
);
dcacheTagLdReg
.valid1(1);
dcacheTagLdReg
.valid0(1);
uint64_t data
= dcacheTagLdReg();
dcacheTag
[dcacheDiagTagAddr()].set(data
);
SS_Trap::Type tt
= strand
[strand_id
]->fill_store_buffer_mem(memXact
);
if(tt
!= SS_Trap::NO_TRAP
)
// Get line from L2 cache
SS_Trap::Type trapNumber
= SS_Trap::NO_TRAP
;
trapNumber
= mem_err_detector
->L2CacheFill(memXact
);
if (trapNumber
!= SS_Trap::NO_TRAP
)
// flip all the parity bits
uint32_t parity
= calc_dcache_parity(dcacheDiagDataLdAddr
);
dcacheDiagDataLdAddr
.data_notparity(0);
N2_DcacheDataStReg dcacheDataStReg
;
dcacheDataStReg
.set(parity
);
dcacheData
[dcacheDiagDataLdAddr()] = dcacheDataStReg
;
uint32_t errorAddr
= index
;
errorAddr
|= hit_way
<< N2_DcacheAddressingFields::bit_size_sets
;
for (uint32_t way
= 0; way
< N2_DcacheAddressingFields::DCACHE_WAYS
; ++way
)
N2_DcacheDiagTagAddrFields dcacheDiagTagAddr
;
dcacheDiagTagAddr
.way(way
);
dcacheDiagTagAddr
.index(index
);
dcacheTag
.erase(dcacheDiagTagAddr());
for (int dword
= 0; dword
< (1<<N2_DcacheDiagDataLdAddrFields::bit_size_doubleword
); dword
++)
N2_DcacheDiagDataLdAddrFields dcacheDiagDataLdAddr
;
dcacheDiagDataLdAddr
.way(way
);
dcacheDiagDataLdAddr
.index(index
);
dcacheDiagDataLdAddr
.doubleword(dword
);
dcacheData
.erase(dcacheDiagDataLdAddr());
dcacheDiagDataLdAddr
.data_notparity(1);
dcacheData
.erase(dcacheDiagDataLdAddr());
dcacheDiagDataLdAddr
.data_notparity(0);
update_clesr(strand_id
, 1, desr
.f());
return SS_Trap::HW_CORRECTED_ERROR
;
// flushDcache() flushes the D-cache line at paddr.
// No RAS correction or detection occurs.
void N2_Core::flush_dcache(uint64_t paddr
)/*{{{*/
if (dcache_empty
) // avoid searching #$ if empty
N2_DcacheAddressingFields pc_pa
;
// Verify correct alignment
/*if (paddr % (1 << N2_DcacheAddressingFields::bitSizeDATA)) {
RS_DOMAIN_ERR("N2_core::flushDcache(): misaligned paddr 0x%ullx",
// Look for a matching line in the cache and invalidate it
search_dcache_tags(pc_pa
, hit_way
);
N2_DcacheTagLdReg dcacheTagLdReg
;
dcacheTagLdReg
.valid1(0);
dcacheTagLdReg
.valid0(0);
N2_DcacheDiagTagAddrFields diagTagAddr
;
diagTagAddr
.index(pc_pa
.sets());
diagTagAddr
.way(hit_way
);
// write the tag into the cache
dcacheTag
[diagTagAddr()] = dcacheTagLdReg
;
// searchDcacheTags() returns the RAS error type found in Tbl. 12-13,
// N2 1.1 PRM. It is passed the physical address to be looked up and
// a reference to the matching way if the address hits in the D-cache.
// If there is no hit, the reference is set to -1.
uint32_t N2_Core::search_dcache_tags(N2_DcacheAddressingFields pa
,int32_t &hit_way
)/*{{{*/
// Dcache has 16 byte lines, with four ways
uint64_t index
= pa
.sets();
char valids
[N2_DcacheAddressingFields::DCACHE_WAYS
];
char perrs
[N2_DcacheAddressingFields::DCACHE_WAYS
];
uint64_t tags
[N2_DcacheAddressingFields::DCACHE_WAYS
];
/* Search all the ways for tag valids and tag valid errors */
for (way
= 0; way
< N2_DcacheAddressingFields::DCACHE_WAYS
; way
++)
N2_DcacheDiagTagAddrFields dcacheDiagTagAddr
;
dcacheDiagTagAddr
.way(way
);
dcacheDiagTagAddr
.index(index
);
N2_DcacheTagLdReg dcacheTagLdReg
= dcacheTag
[dcacheDiagTagAddr()];
if (dcacheTagLdReg
.valid1() != dcacheTagLdReg
.valid0())
valids
[way
] = dcacheTagLdReg
.valid0();
tags
[way
] = dcacheTagLdReg
.tag();
pe
= BL_BitUtility::calc_parity(tags
[way
]);
pe
^= dcacheTagLdReg
.tag_parity();
// next highest priority is D-cache Tag parity
for (way
= 0; way
< N2_DcacheAddressingFields::DCACHE_WAYS
; way
++)
if (valids
[way
] && perrs
[way
])
// next highest priority is d-cache tag multihit
for (way
= 0; way
< N2_DcacheAddressingFields::DCACHE_WAYS
; way
++)
if (valids
[way
] && tag
== tags
[way
])
if (hit_way
!= -1 && cerer
.dctm())
// Calculates the eight parity bits for the Dcache line at
// dcacheDiagDataLdAddr located with diagnostic access
uint32_t N2_Core::calc_dcache_parity(N2_DcacheDiagDataLdAddrFields dcacheDiagDataLdAddr
)/*{{{*/
dcacheDiagDataLdAddr
.data_notparity(1);
N2_DcacheDataStReg dcacheDataStReg
= dcacheData
[dcacheDiagDataLdAddr()];
uint64_t data
= dcacheDataStReg
.data();
return BL_BitUtility::calc_byte_parities(data
);
// Flush all the decode caches associated with this core.
void N2_Core::flush_tte_all()/*{{{*/
for (uint_t strand_ndx
= 0; strand_ndx
< N2_Model::NO_STRANDS_PER_CORE
;
strand
[strand_ndx
]->flush_tte_all();