Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / n2 / lib / cpu / src / N2_Core.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: N2_Core.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
22#include <string.h>
23#include <new>
24#include "N2_Strand.h"
25#include "N2_Core.h"
26#include "N2_Cpu.h"
27#include "BL_BitUtility.h"
28#include "N2_IrfEcc.h"
29#include "N2_FrfEcc.h"
30
31N2_Core::N2_Core( N2_Cpu& _cpu, const char* _name, uint_t strand_id_base )/*{{{*/
32 :
33 SS_Node(_cpu,_name),
34 cpu(_cpu),
35 inst_tlb(SS_Tlb::INST_TLB,N2_Tlb::ITLB_SIZE),
36 data_tlb(SS_Tlb::DATA_TLB,N2_Tlb::DTLB_SIZE),
37 icache_empty(true),
38 dcache_empty(true)
39{
40 for (uint_t i=0; i < N2_Model::NO_STRANDS_PER_CORE; i++)
41 {
42 char num[8];
43 sprintf(num,"s%i",i);
44 void* s = ss_memalign(64,sizeof(N2_Strand));
45 new(s) N2_Strand(*this,num,strand_id_base + i);
46 strand[i] = (N2_Strand*)s;
47 }
48
49 asi_map[0x42].add(0x08,0x08,this,0,
50 inst_iw_ld64,inst_iw_st64,
51 inst_iw_ld64,inst_iw_st64);
52
53 asi_map[0x42].add(0x10,this,lsu_diag);
54 asi_map[0x43].add(0x00,this,&error_inject,
55 SS_SharedAsiCtrReg::ld64,error_inject_st64,
56 SS_SharedAsiCtrReg::rd64,error_inject_st64);
57 asi_map[0x45].add(0x08,this,decr);
58
59 asi_map[0x46].set_mask(N2_DcacheDataStReg::DCACHE_DATA_SIZE_MASK);
60 asi_map[0x46].add(SS_VADDR_MIN,SS_VADDR_MAX,this,0,
61 dcache_data_ld64,dcache_data_st64,
62 dcache_data_ld64,dcache_data_st64);
63
64 asi_map[0x47].set_mask(N2_DcacheTagLdReg::DCACHE_TAG_SIZE_MASK);
65 asi_map[0x47].add(0x0,(N2_DcacheTagLdReg::DCACHE_TAG_SIZE_MASK -1),this,0,
66 dcache_tag_ld64,dcache_tag_st64,
67 dcache_tag_ld64,dcache_tag_st64);
68
69 asi_map[0x4c].add(0x08,this,&dfesr,
70 SS_SharedAsiCtrReg::ld64,0,
71 SS_SharedAsiCtrReg::rd64,SS_SharedAsiCtrReg::wr64);
72
73 asi_map[0x4c].add(0x10,this,cerer);
74
75 asi_map[0x4c].add(0x20,this,&clesr,
76 SS_SharedAsiCtrReg::ld64,0,
77 SS_SharedAsiCtrReg::rd64,0);
78
79 asi_map[0x4c].add(0x28,this,&clfesr,
80 SS_SharedAsiCtrReg::ld64,0,
81 SS_SharedAsiCtrReg::rd64,0);
82
83 asi_map[0x4e].add(0x00,this,power_mgmt);
84
85 asi_map[0x50].add(0x38,0x38,this,0,
86 inst_wp_ld64,inst_wp_st64,
87 inst_wp_ld64,inst_wp_st64);
88
89 asi_map[0x54].add(0x98,this,&tw_status,
90 tw_status_ld64,0,
91 tw_status_ld64,SS_SharedAsiCtrReg::wr64);
92
93 asi_map[0x66].set_mask(N2_IcacheInstrStReg::ICACHE_DATA_SIZE_MASK);
94 asi_map[0x66].add(0x0,(N2_IcacheInstrStReg::ICACHE_DATA_SIZE_MASK -1),this,0,
95 icache_data_ld64,icache_data_st64,
96 icache_data_ld64,icache_data_st64);
97
98 asi_map[0x67].set_mask(N2_IcacheTagLdReg::ICACHE_TAG_SIZE_MASK);
99 asi_map[0x67].add(0x0,(N2_IcacheTagLdReg::ICACHE_TAG_SIZE_MASK -1),this,0,
100 icache_tag_ld64,icache_tag_st64,
101 icache_tag_ld64,icache_tag_st64);
102}
103/*}}}*/
104N2_Core::~N2_Core()/*{{{*/
105{
106}
107/*}}}*/
108
109void N2_Core::hard_reset()/*{{{*/
110{
111 for (uint s=0; s < N2_Model::NO_STRANDS_PER_CORE; s++)
112 ((N2_Strand*)strand[s])->hard_reset();
113}
114/*}}}*/
115void N2_Core::warm_reset(bool intp)/*{{{*/
116{
117 lsu_diag = 0;
118 error_inject = 0;
119 decr = 0;
120 cerer = 0;
121 power_mgmt = 0;
122 inst_iw[0] = 0;
123 inst_iw[1] = 0;
124
125 for (uint s=0; s < N2_Model::NO_STRANDS_PER_CORE; s++)
126 ((N2_Strand*)strand[s])->warm_reset(intp);
127}
128/*}}}*/
129void N2_Core::snapshot( SS_SnapShot& ss )/*{{{*/
130{
131 char prefix[32];
132 get_name(prefix);
133
134 power_mgmt.snapshot(ss,prefix);
135 error_inject.snapshot(ss,prefix);
136 decr.snapshot(ss,prefix);
137 dfesr.snapshot(ss,prefix);
138 cerer.snapshot(ss,prefix);
139 clesr.snapshot(ss,prefix);
140 clfesr.snapshot(ss,prefix);
141
142 SS_SharedAsiCtrReg::snapshot(ss,inst_iw,2,prefix);
143 SS_SharedAsiCtrReg::snapshot(ss,inst_wp,2,prefix);
144
145 lsu_diag.snapshot(ss,prefix);
146
147 for (int s=0; s < N2_Model::NO_STRANDS_PER_CORE; s++)
148 strand[s]->snapshot(ss);
149
150 inst_tlb.snapshot(ss,prefix,"inst");
151 data_tlb.snapshot(ss,prefix,"data");
152
153 // Deal with loaded values that need to propagate through the
154 // model into the strands etc.
155
156 if (ss.do_load())
157 {
158 // Deal with values that have sife effecrts when written to.
159 // This to ensure everything is updated. We reuse thet asi st64
160 // functions for this and pass sensible values for unused parameters.
161
162 inst_iw_st64(this,0,strand[0],0,inst_iw[0]());
163 inst_iw_st64(this,0,strand[2],0,inst_iw[1]());
164 inst_wp_st64(this,0,strand[0],0,inst_wp[0]());
165 inst_wp_st64(this,0,strand[2],0,inst_wp[1]());
166 }
167}
168/*}}}*/
169
170void N2_Core::ras_enable(char*)/*{{{*/
171{
172 for (int s=0; s < N2_Model::NO_STRANDS_PER_CORE; s++)
173 strand[s]->ras_enable(strand[s], NULL);
174}
175/*}}}*/
176
177
178SS_AsiSpace::Error N2_Core::inst_iw_ld64( SS_Node* _core, void*, SS_Strand* s, SS_Vaddr va , uint64_t* data )/*{{{*/
179{
180 N2_Core* core = (N2_Core*)_core;
181 N2_InstMask* r = &core->inst_iw[(s->strand_id() >> 2) & 1];
182 *data = r->get();
183 return SS_AsiSpace::OK;
184}
185/*}}}*/
186SS_AsiSpace::Error N2_Core::inst_iw_st64( SS_Node* _core, void*, SS_Strand* s, SS_Vaddr va, uint64_t data )/*{{{*/
187{
188 N2_Core* core = (N2_Core*)_core;
189 uint_t i = s->strand_id() & 4;
190 N2_InstMask* r = &core->inst_iw[i >> 2];
191 r->lock();
192 r->set(data);
193
194 uint32_t iw_mask = 0;
195
196 if (r->en_rs2()) iw_mask |= 0x1f;
197 if (r->en_asi()) iw_mask |= 0xff << 5;
198 if (r->en_i()) iw_mask |= 0x01 << 13;
199 if (r->en_rs1()) iw_mask |= 0x1f << 14;
200 if (r->en_op3()) iw_mask |= 0x3f << 19;
201 if (r->en_rd()) iw_mask |= 0x1f << 25;
202 if (r->en_op()) iw_mask |= 0x03 << 30;
203
204 uint32_t iw_data = r->iw() & iw_mask;
205
206 core->strand[i ]->inst_breakpoint_set(0,iw_mask,iw_data);
207 core->strand[i + 1]->inst_breakpoint_set(0,iw_mask,iw_data);
208 core->strand[i + 2]->inst_breakpoint_set(0,iw_mask,iw_data);
209 core->strand[i + 3]->inst_breakpoint_set(0,iw_mask,iw_data);
210
211 r->unlock();
212 return SS_AsiSpace::OK;
213}
214/*}}}*/
215
216SS_AsiSpace::Error N2_Core::inst_wp_ld64( SS_Node* _core, void*, SS_Strand* s, SS_Vaddr va , uint64_t* data )/*{{{*/
217{
218 N2_Core* core = (N2_Core*)_core;
219 uint_t i = s->strand_id() & 4;
220 N2_InstWp* r = &core->inst_wp[i >> 2];
221 *data = r->get(); // Signextended on store
222 return SS_AsiSpace::OK;
223}
224/*}}}*/
225SS_AsiSpace::Error N2_Core::inst_wp_st64( SS_Node* _core, void*, SS_Strand* s, SS_Vaddr va, uint64_t data )/*{{{*/
226{
227 N2_Core* core = (N2_Core*)_core;
228 uint_t i = s->strand_id() & 4;
229 N2_InstWp* r = &core->inst_wp[i >> 2];
230
231 r->lock();
232
233 uint64_t old_enabled = r->enabled();
234
235 // Sign extend from bit47 up now which saves a shift later in use :-)
236 // but first clip of the bits that are RO.
237
238 r->set(data);
239 r->set_unmasked((SS_Vaddr(r->get()) << (64 - s->va_bits())) >> (64 - s->va_bits()));
240
241 // Bit0 of the address is used to indicate enabled (0) or disabled (1)
242 // This saves an extra compare, eg. bit 0 of the PC is always 0
243 // so a disabled watchpoint has the address bit0 set, so addr won't
244 // compare equal to the PC when disabled - ever.
245
246 SS_Vaddr addr = (r->va() << 2) + !r->enabled();
247 SS_Vaddr mask = (SS_Vaddr(1) << 48) - 4;
248
249 core->strand[i ]->inst_watchpoint_va_set(mask,addr);
250 core->strand[i + 1]->inst_watchpoint_va_set(mask,addr);
251 core->strand[i + 2]->inst_watchpoint_va_set(mask,addr);
252 core->strand[i + 3]->inst_watchpoint_va_set(mask,addr);
253
254 // On every watchpoint change we signal flush decode caches to
255 // all strands ... as we use the decode cache to store special
256 // decoders that have knowledge about the watchpoints.
257
258 SS_Signal* sgn;
259 sgn = s->msg.make_signal(SS_Signal::FLUSH_VA);
260 sgn->flush_va = addr;
261 core->strand[i]->post_signal(sgn);
262 sgn = s->msg.make_signal(SS_Signal::FLUSH_VA);
263 sgn->flush_va = addr;
264 core->strand[i + 1]->post_signal(sgn);
265 sgn = s->msg.make_signal(SS_Signal::FLUSH_VA);
266 sgn->flush_va = addr;
267 core->strand[i + 2]->post_signal(sgn);
268 sgn = s->msg.make_signal(SS_Signal::FLUSH_VA);
269 sgn->flush_va = addr;
270 core->strand[i + 3]->post_signal(sgn);
271
272 r->unlock();
273 return SS_AsiSpace::OK;
274}
275/*}}}*/
276
277SS_AsiSpace::Error N2_Core::icache_tag_ld64( SS_Node* _core, void*, SS_Strand* s, SS_Vaddr va , uint64_t* data )/*{{{*/
278{
279 N2_Core* core = (N2_Core*)_core;
280 // convert ASI_VA to hardware index/way
281 N2_IcacheDiagTagAddrFields diagTagAddr;
282 diagTagAddr.set(va);
283 diagTagAddr.perren(0);// clear the err inject and valid bits
284 diagTagAddr.vb_err_en(0); // before accessing the ASI map
285
286 *data = (core->icacheTag.get(diagTagAddr))();
287
288 return SS_AsiSpace::OK;
289}
290/*}}}*/
291SS_AsiSpace::Error N2_Core::icache_tag_st64( SS_Node* _core, void*, SS_Strand*, SS_Vaddr va, uint64_t data )/*{{{*/
292{
293 N2_Core* core = (N2_Core*)_core;
294 // ASI VA for tag contains, way/index,
295 // parity error enable and vb_err_enable
296 N2_IcacheDiagTagAddrFields vaddr;
297 vaddr.set(va);
298 N2_IcacheDiagTagAddrFields indexVa = vaddr;
299 indexVa.perren(0); // clear the err inject and valid bits
300 indexVa.vb_err_en(0); // before accessing the ASI map
301
302 N2_IcacheTagLdReg icacheTagLdReg;
303 icacheTagLdReg.set(data);
304
305 // calculate parity over tag
306
307 uint64_t t = BL_BitUtility::calc_parity(icacheTagLdReg.tag());
308 t ^= vaddr.perren(); // invert parity if perren is one
309
310 // merge tag and parity
311
312 icacheTagLdReg.tag_parity(t);
313
314 // enforce valid bit error injection enable
315
316 icacheTagLdReg.valid0(icacheTagLdReg.valid1() ^ vaddr.vb_err_en());
317
318 // write the tag back into the cache
319 core->icacheTag.set(indexVa, icacheTagLdReg);
320
321 /* Flush all the decode caches associated with this core */
322 core->flush_tte_all();
323
324 return SS_AsiSpace::OK;
325}
326/*}}}*/
327SS_AsiSpace::Error N2_Core::icache_data_ld64( SS_Node* _core, void*, SS_Strand* s, SS_Vaddr va , uint64_t* data )/*{{{*/
328{
329 N2_Core* core = (N2_Core*)_core;
330 // convert ASI_VA to hardware index/way
331 N2_IcacheDiagInstrAddrFields diagInstrAddr;
332 diagInstrAddr.set(va);
333
334 uint64_t index = diagInstrAddr();
335 *data = core->icacheInstr[index]();
336
337 return SS_AsiSpace::OK;
338}
339/*}}}*/
340SS_AsiSpace::Error N2_Core::icache_data_st64( SS_Node* _core, void*, SS_Strand*, SS_Vaddr va, uint64_t data )/*{{{*/
341{
342 N2_Core* core = (N2_Core*)_core;
343 // extract icache perrinj, way, and index from ASI_VA
344 N2_IcacheDiagInstrAddrFields vaddr;
345 vaddr.set(va);
346 uint64_t index = vaddr();
347
348 N2_IcacheInstrStReg icacheInstrStReg;
349 icacheInstrStReg.set(data);
350 // enforce perrinj
351
352 uint32_t t = BL_BitUtility::calc_parity(icacheInstrStReg.instr());
353 t ^= icacheInstrStReg.perrinj();
354
355 // merge parity into data
356
357 icacheInstrStReg.perrinj(t);
358
359 // write the data (instr) into the I-cache
360 core->icacheInstr[index] = icacheInstrStReg;
361
362 return SS_AsiSpace::OK;
363}
364/*}}}*/
365
366SS_AsiSpace::Error N2_Core::dcache_tag_ld64( SS_Node* _core, void*, SS_Strand* s, SS_Vaddr va , uint64_t* data )/*{{{*/
367{
368 N2_Core* core = (N2_Core*)_core;
369 N2_DcacheDiagTagAddrFields dcacheDiagTagAddr;
370 dcacheDiagTagAddr.set(va);
371
372 *data = (core->dcacheTag[dcacheDiagTagAddr()])();
373
374 return SS_AsiSpace::OK;
375}
376/*}}}*/
377SS_AsiSpace::Error N2_Core::dcache_tag_st64( SS_Node* _core, void*, SS_Strand*, SS_Vaddr va, uint64_t data )/*{{{*/
378{
379 N2_Core* core = (N2_Core*)_core;
380 // ASI_VA contains valid bit error enable (vb_err_en)
381 // parity error enable (perren)
382 // way and index (way_index)
383 N2_DcacheDiagTagAddrFields vaddr;
384 vaddr.set(va);
385 uint64_t vb_err_en = vaddr.vb_err_en();
386 uint64_t perren = vaddr.perren();
387 uint64_t parity;
388
389 // clear out reserved bits from the data
390
391 N2_DcacheTagLdReg dcacheTagLdReg;
392 dcacheTagLdReg.set(data);
393
394 // calculate parity over tag and tag valid
395
396 parity = BL_BitUtility::calc_parity(dcacheTagLdReg.tag());
397 parity ^= perren;
398
399 // merge parity and valid bits
400
401 dcacheTagLdReg.tag_parity(parity);
402 dcacheTagLdReg.valid0(dcacheTagLdReg.valid1() ^ vb_err_en);
403
404 vaddr.vb_err_en(0);
405 vaddr.perren(0);
406 // write it into the D$ tag
407 core->dcacheTag[vaddr()].set(dcacheTagLdReg());
408
409 return SS_AsiSpace::OK;
410}
411/*}}}*/
412SS_AsiSpace::Error N2_Core::dcache_data_ld64( SS_Node* _core, void*, SS_Strand* s, SS_Vaddr va , uint64_t* data )/*{{{*/
413{
414 N2_Core* core = (N2_Core*)_core;
415 N2_DcacheDiagDataLdAddrFields dcacheDiagDataLdAddr;
416 dcacheDiagDataLdAddr.set(va);
417 *data = (core->dcacheData[dcacheDiagDataLdAddr()])();
418
419 return SS_AsiSpace::OK;
420}
421/*}}}*/
422SS_AsiSpace::Error N2_Core::dcache_data_st64( SS_Node* _core, void*, SS_Strand*, SS_Vaddr va, uint64_t data )/*{{{*/
423{
424 N2_Core* core = (N2_Core*)_core;
425 // ASI VA contains D$ index, and parity error injection mask
426 N2_DcacheDiagDataStAddrFields vaddr;
427 vaddr.set(va);
428 uint64_t index = vaddr.index();
429 uint64_t perrmask = vaddr.perrmask();
430 uint64_t parity;
431
432 // record the parity
433
434 parity = BL_BitUtility::calc_byte_parities(data);
435
436 parity ^= perrmask;
437
438 // This ends up being a write to data *and* parity
439 N2_DcacheDiagDataLdAddrFields ldVa;
440 ldVa.index(index);
441 ldVa.way(vaddr.way());
442
443 // Write the parity into the cache
444 core->dcacheData[ldVa()].set(parity);
445
446 ldVa.data_notparity(1);
447 core->dcacheData[ldVa()].set(data);
448
449 return SS_AsiSpace::OK;
450}
451/*}}}*/
452
453SS_AsiSpace::Error N2_Core::tw_status_ld64( SS_Node* _core, void*, SS_Strand* s, SS_Vaddr va , uint64_t* data )/*{{{*/
454{
455 N2_Core* core = (N2_Core*)_core;
456
457 uint_t tws = 0;
458 for (uint_t i=0; i < N2_Model::NO_STRANDS_PER_CORE; i++)
459 tws |= core->strand[i]->tw_status << i;
460
461 core->tw_status.lock();
462 core->tw_status.htp(tws);
463 *data = core->tw_status();
464 core->tw_status.unlock();
465
466 return SS_AsiSpace::OK;
467}
468/*}}}*/
469
470SS_AsiSpace::Error N2_Core::error_inject_st64( SS_Node* _core, void* _reg, SS_Strand* , SS_Vaddr, uint64_t data )/*{{{*/
471{
472 N2_Core* core = (N2_Core*)_core;
473 N2_ErrorInject* reg = (N2_ErrorInject*) _reg;
474
475 reg->set(data);
476
477 /* If IRF/FRF injection is set , then enable the inject/detect in RAS mode */
478 /* for performance reasons these are not enabled immediately while transitioning to RAS mode */
479 if(reg->ircu())
480 {
481 for (uint_t ndx = 0; ndx < N2_Model::NO_STRANDS_PER_CORE; ++ndx)
482 {
483 N2_Strand* s = core->strand[ndx];
484 if(s->sim_state.ras_enabled())
485 {
486 s->ras_rs1 = n2_irf_ras_detect;
487 s->ras_rs2 = n2_irf_ras_detect;
488 s->ras_rs3 = n2_irf_ras_detect;
489 s->ras_rd = n2_irf_ras_inject;
490 }
491 }
492 }
493
494 if(reg->frcu())
495 {
496 for (uint_t ndx = 0; ndx < N2_Model::NO_STRANDS_PER_CORE; ++ndx)
497 {
498 N2_Strand* s = core->strand[ndx];
499 if(s->sim_state.ras_enabled())
500 {
501 s->ras_frs1 = n2_frf_ras_detect;
502 s->ras_frs2 = n2_frf_ras_detect;
503 s->ras_frs3 = n2_frf_ras_detect;
504 s->ras_frd = n2_frf_ras_inject;
505
506 s->ras_drs1 = n2_frf_dp_ras_detect;
507 s->ras_drs2 = n2_frf_dp_ras_detect;
508 s->ras_drs3 = n2_frf_dp_ras_detect;
509 s->ras_drd = n2_frf_dp_ras_inject;
510 }
511 }
512 }
513
514 return SS_AsiSpace::OK;
515}
516/*}}}*/
517
518/* RAS Routines */
519
520void N2_Core::update_clesr(int sid, int isDesr, uint64_t value)/*{{{*/
521{
522 // 'value' is either desr or dfesr's F field, record it in clesr's
523 // corresponding bit location
524 int shift = 48 + (sid * 2) + isDesr;
525 uint64_t mask = 1 << shift;
526 uint64_t data = value << shift;
527 uint64_t origData = clesr.get();
528 uint64_t newData = (origData & ~mask) | data;
529 clesr.set(newData);
530 if (value != 0)
531 {
532 if ((clfesr.get() & mask) == 0)
533 {
534 // the corresponding bit in clfesr is not set, record the new value
535 origData = clfesr.get();
536 newData = (origData & ~mask) | data;
537 clfesr.set(newData);
538 }
539 }
540 else if (clesr.get() == 0)
541 {
542 // clesr is clear, so go ahead and clear clfesr
543 clfesr.set(0);
544 }
545}
546/*}}}*/
547
548
549SS_Trap::Type N2_Core::icache_ifetch(
550 const MemoryTransaction &memXact,
551 bool trap_enabled,
552 uint32_t strand_id,
553 N2_MemErrDetector *mem_err_detector)/*{{{*/
554{
555
556 /***************************************************
557 * Adding I-cache RAS error check here inline, because
558 * I'm not quite sure where else to add it
559 *
560 * The map icacheTag_ contains all the tags for this
561 * core.
562 * The map icacheData_ contains all the data for this
563 * core
564 *
565 * Algorithm:
566 * 1. Search for tag valid errors
567 * DESR = ICVP
568 * trap_type = HW_CORRECTED_ERROR
569 * 2. Search for tag parity errors
570 * DESR = ICTP
571 * trap_type = HW_CORRECTED_ERROR
572 * 3. Search for hit and multi-hit errors
573 * DESR = ICTM
574 * trap_type = HW_CORRECTED_ERROR
575 * 4. If line in cache
576 * if instruction parity error
577 * DESR = ICTM
578 * trap_type = HW_CORRECTED_ERROR
579 * 5. if line not in cache
580 * pick and allocate L1 way
581 * for each instr in line
582 * set good instr parity
583 * set good tag parity/valid
584 *
585 ***************************************************/
586
587 // Split physical address into icache index and tag
588
589 N2_IcacheAddressingFields pc_pa;
590 pc_pa.set(memXact.getPaddr());
591 uint64_t index = pc_pa.sets(); // Tbl B-2 refers to SET
592 // Tbl 28-8 and -10 to index
593 uint64_t tag = pc_pa.tag();
594 N2_Desr &desr = strand[strand_id]->desr;
595
596 icache_empty = false; // remember the I$ has been used
597
598 int32_t hit_way = -1;
599 uint32_t errortype = search_icache_tags(pc_pa, hit_way);
600
601 // if there were no errors and we got a hit, then lets check the
602 // addressed instruction for parity error
603
604 if (errortype == 0 && hit_way != -1)
605 {
606 uint32_t way = hit_way;
607 N2_IcacheDiagInstrAddrFields diagInstrAddr;
608 diagInstrAddr.index(index);
609 diagInstrAddr.way(way);
610 diagInstrAddr.word(pc_pa.instr()); // WORD == INSTR in PRM
611
612 N2_IcacheInstrStReg icacheInstrStReg = icacheInstr[diagInstrAddr()];
613 uint32_t pe = icacheInstrStReg.instr(); // extract instruction
614
615 // calculate parity over instruction
616 pe = BL_BitUtility::calc_parity(pe);
617 pe ^= icacheInstrStReg.perrinj(); // xor in parity bit
618
619 // if this comes up one then we have a parity error
620 if (pe && cerer.icdp())
621 {
622 errortype = 4;
623 }
624 }
625
626 // all done checking for errors
627
628 if (errortype == 0)
629 {
630 // no errors. If we got a miss (no tag match), then create a new
631 // line in the cache (possibly overwriting a currently valid entry)
632
633 if (hit_way == -1)
634 {
635
636 // we didn't get a tag match
637
638 //TODO: Handle NotData poison here.
639 SS_Trap::Type trapNumber = SS_Trap::NO_TRAP;
640 if(mem_err_detector)
641 {
642 trapNumber = mem_err_detector->L2CacheFill(memXact);
643 }
644
645 // For now, just create a clean line with valid tag
646
647 uint32_t way = (icache_lru++ % N2_IcacheAddressingFields::ICACHE_WAYS);
648 N2_IcacheDiagInstrAddrFields diagInstrAddr;
649 diagInstrAddr.index(index);
650 diagInstrAddr.way(way);
651
652 // Clean out any old errors
653
654 for (int word = 0; word < 8; word++)
655 {
656 diagInstrAddr.word(word);
657 icacheInstr.erase(diagInstrAddr());
658 if (trapNumber != SS_Trap::NO_TRAP)
659 {
660 N2_IcacheInstrStReg &icacheInstrStReg = icacheInstr[diagInstrAddr()];
661 icacheInstrStReg.set(0);
662 icacheInstrStReg.perrinj(1);
663 }
664 }
665
666 // calculate tag parity
667
668 int64_t tag_pe = BL_BitUtility::calc_parity(tag);
669
670 // format tag entry in ASI format
671
672 N2_IcacheTagLdReg obj;
673 obj.tag(tag);
674 obj.tag_parity(tag_pe);
675 obj.valid1(1);
676 obj.valid0(1);
677
678 N2_IcacheDiagTagAddrFields diagTagAddr;
679 diagTagAddr.index(index);
680 diagTagAddr.way(way);
681
682 // write the tag into the cache
683 icacheTag.set(diagTagAddr, obj);
684
685 if (trapNumber != SS_Trap::NO_TRAP)
686 {
687 return trapNumber;
688 }
689 // Now poison all matching decode cache entries
690 strand[strand_id]->flush(pc_pa(), true);
691 }
692 } else
693 {
694 // errortype != 0
695
696 // we detected some kind of error (recorded in errortype)
697 // we try to record into Disrupting Error Status Register (DESR)
698
699 if (desr.f() == 0)
700 { // record the error address if not full
701 desr.erraddr((hit_way << 6) | (pc_pa.sets()));
702 }
703
704 // hardware automatically recovers from this error by erasing
705 // all ways in the set
706 for (uint32_t way = 0; way < N2_IcacheAddressingFields::ICACHE_WAYS; way++)
707 {
708 N2_IcacheDiagTagAddrFields diagTagAddr;
709 diagTagAddr.index(index);
710 diagTagAddr.way(way);
711
712 N2_IcacheTagLdReg tagReg = icacheTag.get(diagTagAddr);
713 tagReg.valid0(0);
714 tagReg.valid1(0);
715 icacheTag.set(diagTagAddr, tagReg);
716
717 N2_IcacheDiagInstrAddrFields diagInstrAddr;
718 diagInstrAddr.index(index);
719 diagInstrAddr.way(way);
720 for (int word = 0; word < 8; word++)
721 {
722 diagInstrAddr.word(word);
723 icacheInstr.erase(diagInstrAddr());
724 }
725 }
726
727 // if DESR not full, record error type, and mark it full
728
729 if (desr.f() == 0)
730 {
731 // FIXME: set the CLESR.T field for this strand
732 desr.f(1);
733 desr.s(0);
734 desr.errtype(errortype);
735 } else
736 {
737 // if DESR was already full, indicate multiple error
738 desr.me(1);
739 }
740 update_clesr(strand_id, 1, desr.f());
741 if (trap_enabled)
742 {
743 return SS_Trap::HW_CORRECTED_ERROR;
744 }
745 }
746 return SS_Trap::NO_TRAP;
747}
748/*}}}*/
749
750// flushIcache() flushes the I-cache line at paddr.
751//
752// No RAS correction or detection occurs.
753
754void N2_Core::flush_icache(uint64_t paddr)/*{{{*/
755{
756 if (icache_empty) // avoid searching I$ if empty
757 return;
758
759 N2_IcacheAddressingFields pc_pa;
760 pc_pa.set(paddr);
761
762 // Verify correct alignment
763 if (paddr % (1 <<
764 (N2_IcacheAddressingFields::WIDTH_RSVD0 +
765 N2_IcacheAddressingFields::WIDTH_INSTR))) {
766 fprintf(stderr, "Internal error: N2_core::flushIcache(): "
767 "misaligned paddr 0x%ullx", paddr);
768 exit(1);
769 }
770
771 // Look for a matching line in the cache and invalidate it
772 int32_t hit_way;
773 search_icache_tags(pc_pa, hit_way);
774
775 if (hit_way != -1)
776 {
777 N2_IcacheTagLdReg icacheTagLdReg;
778 icacheTagLdReg.valid1(0);
779 icacheTagLdReg.valid0(0);
780
781 N2_IcacheDiagTagAddrFields diagTagAddr;
782 diagTagAddr.index(pc_pa.sets());
783 diagTagAddr.way(hit_way);
784
785 // write the tag into the cache
786 icacheTag.set(diagTagAddr, icacheTagLdReg);
787 }
788}
789/*}}}*/
790
791// searchIcacheTags() returns the RAS error type found in Tbl. 12-13,
792// N2 1.1 PRM. It is passed the physical address to be looked up and
793// a reference to the matching way if the address hits in the I-cache.
794// If there is no hit, the reference is set to -1.
795//
796// A subset of the physical address, called index, gets us down to a
797// set of 8 places where our instructions might be. A given entry in
798// our set of 8 is called a way.
799// A given way contains:
800// room for 8 instructions (32 bytes aligned on 32 byte boundary)
801// valid bit(s) so we know if the instructions are meaningful
802// tag - the bits of the physical address not used as index or to
803// address individual instructions
804// RAS elements
805// each instruction has a parity bit (even parity)
806// tag valid is duplicated (parity)
807// tag has parity (even parity)
808
809uint32_t N2_Core::search_icache_tags(N2_IcacheAddressingFields paddr,int32_t &hit_way)/*{{{*/
810{
811 hit_way = -1;
812
813 uint64_t index = paddr.sets(); // Tbl B-2 refers to SET
814 // Tbl 28-8 and -10 to index
815 uint64_t tag = paddr.tag();
816 uint32_t way;
817
818 char valids[N2_IcacheAddressingFields::ICACHE_WAYS];
819 char perrs[N2_IcacheAddressingFields::ICACHE_WAYS];
820 uint64_t tags[N2_IcacheAddressingFields::ICACHE_WAYS];
821
822 // walk through the tag array finding out which tags are valid
823 // and checking for tag valid errors
824 // eight ways
825 for (way = 0; way < N2_IcacheAddressingFields::ICACHE_WAYS; way++)
826 {
827 N2_IcacheDiagTagAddrFields diagTagAddr;
828 diagTagAddr.index(index);
829 diagTagAddr.way(way);
830
831 // use way and index to look up tags in map
832
833 N2_IcacheTagLdReg icacheTagLdReg = icacheTag.get(diagTagAddr);
834 // tag found in map (may have valids == 0)
835 valids[way] = (icacheTagLdReg.valid1() << 1) | icacheTagLdReg.valid0();
836
837 // check valids (Should be the same, so 0 and 3 are good, 1 and 2 bad)
838 if (valids[way] == 1 || valids[way] == 2)
839 {
840 if (cerer.icvp()) { // I-cache Valid Parity Error
841 hit_way = way;
842 return 1;
843 }
844 }
845
846 // extract the tag (address bits)
847
848 tags[way] = icacheTagLdReg.tag();
849
850 // calculate tag parity using log2 N based XOR trick
851
852 uint64_t pe;
853 pe = BL_BitUtility::calc_parity(tags[way]);
854 pe ^= icacheTagLdReg.tag_parity();
855
856 perrs[way] = pe;
857 }
858
859 // if there were no tag valid errors, check for tag parity errors
860
861 for (way = 0; way < N2_IcacheAddressingFields::ICACHE_WAYS; way++)
862 {
863 if (valids[way] && perrs[way] && cerer.ictp())
864 {
865 // we got valid tag, with errors and we're enabled for
866 // reporting in CERER
867 hit_way = way;
868 return 2;
869 }
870 }
871
872 // if there were no tag parity errors, look for tag matching the
873 // requesting physical address. If there is more than one tag
874 // match try to report tag multi-hit error (if CERER allows)
875
876 bool hit = false;
877 for (way = 0; way < N2_IcacheAddressingFields::ICACHE_WAYS; way++)
878 {
879 if (valids[way] && tag == tags[way])
880 {
881 // tag match
882 if (hit && cerer.ictm())
883 {
884 // if we already had tag hit, and CERER allows report
885 // tag multi-hit
886 hit_way = way;
887 return 3;
888 }
889 // remember that we got a tag match, and remember the way
890 hit = true;
891 hit_way = way;
892 }
893 }
894
895 return 0;
896}
897/*}}}*/
898
899SS_Trap::Type N2_Core::dcache_trans( const MemoryTransaction &memXact,
900 bool trap_enabled,
901 uint32_t strand_id,
902 bool store_id,
903 N2_MemErrDetector *mem_err_detector)/*{{{*/
904{
905
906 /***************************************************
907 * The map dcacheTag_ contains all the tags for this
908 * core.
909 * The map dcacheData_ contains all the data and
910 * parity for this core
911 *
912 * Algorithm:
913 * 1. Search for tag valid errors
914 * DESR = DCVP
915 * trap_type = HW_CORRECTED_ERROR
916 * 2. Search for tag parity errors
917 * DESR = DCTP
918 * trap_type = HW_CORRECTED_ERROR
919 * 3. Search for hit and multi-hit errors
920 * DESR = DCTM
921 * trap_type = HW_CORRECTED_ERROR
922 * 4. If line in cache
923 * if instruction parity error
924 * DESR = DCTM
925 * trap_type = HW_CORRECTED_ERROR
926 * 5. if line not in cache
927 * pick and allocate L1 way
928 * for each instr in line
929 * set good instr parity
930 * set good tag parity/valid
931 *
932 ***************************************************/
933
934 N2_Desr &desr = strand[strand_id]->desr;
935
936 N2_DcacheAddressingFields paddr;
937 paddr.set(memXact.getPaddr());
938 uint64_t index = paddr.sets();
939 uint64_t tag = paddr.tag();
940 uint64_t dw = paddr.data();
941
942 dcache_empty = false; // remember the D$ has been used
943
944 int32_t hit_way;
945 uint32_t errortype = search_dcache_tags(paddr, hit_way);
946
947 if (errortype == 0)
948 {
949 // no errors so far
950 if (hit_way != -1)
951 {
952 // we found a tag match (hit) so check data parity
953 uint32_t way = hit_way;
954
955 N2_DcacheDiagDataLdAddrFields dcacheDiagDataLdAddr;
956 dcacheDiagDataLdAddr.way(way);
957 dcacheDiagDataLdAddr.index(index);
958 dcacheDiagDataLdAddr.doubleword(dw);
959
960 N2_DcacheDataStReg dcacheDataStReg = dcacheData[dcacheDiagDataLdAddr()];
961 uint64_t parity = dcacheDataStReg.data();
962
963 if (calc_dcache_parity(dcacheDiagDataLdAddr) != parity && memXact.readXact())
964 {
965 if (cerer.dcdp())
966 {
967 errortype = 8;
968 }
969 }
970 // writes update the dirty bits in the L2$
971 if (memXact.writeXact()/* || memXact.rdwrXact()*/)
972 {
973 SS_Trap::Type tt = strand[strand_id]->fill_store_buffer_mem(memXact);
974 if(tt != SS_Trap::NO_TRAP)
975 return tt;
976
977 if(mem_err_detector){
978 SS_Trap::Type tt = mem_err_detector->L2CacheFill(memXact);
979 if(tt != SS_Trap::NO_TRAP)
980 return tt;
981 }
982 }
983 } else
984 {
985 // Create a clean line with valid tag
986
987 uint32_t way = (dcache_lru++ % N2_DcacheAddressingFields::DCACHE_WAYS);
988
989 N2_DcacheDiagDataLdAddrFields dcacheDiagDataLdAddr;
990 dcacheDiagDataLdAddr.way(way);
991 dcacheDiagDataLdAddr.index(index);
992
993 for (int dword = 0; dword < (1<<N2_DcacheDiagDataLdAddrFields::bit_size_doubleword); dword++)
994 {
995 dcacheDiagDataLdAddr.doubleword(dw);
996 dcacheData.erase(dcacheDiagDataLdAddr());
997 dcacheDiagDataLdAddr.data_notparity(1);
998 dcacheData.erase(dcacheDiagDataLdAddr());
999 dcacheDiagDataLdAddr.data_notparity(0);
1000 }
1001
1002 int64_t tag_pe = BL_BitUtility::calc_parity(tag);
1003
1004 N2_DcacheDiagTagAddrFields dcacheDiagTagAddr;
1005 dcacheDiagTagAddr.way(way);
1006 dcacheDiagTagAddr.index(index);
1007
1008 N2_DcacheTagLdReg dcacheTagLdReg;
1009 dcacheTagLdReg.tag(tag);
1010 dcacheTagLdReg.tag_parity(tag_pe);
1011 dcacheTagLdReg.valid1(1);
1012 dcacheTagLdReg.valid0(1);
1013
1014 uint64_t data = dcacheTagLdReg();
1015 dcacheTag[dcacheDiagTagAddr()].set(data);
1016
1017 if (memXact.writeXact())
1018 {
1019 SS_Trap::Type tt = strand[strand_id]->fill_store_buffer_mem(memXact);
1020 if(tt != SS_Trap::NO_TRAP)
1021 return tt;
1022 }
1023
1024 // Get line from L2 cache
1025 SS_Trap::Type trapNumber = SS_Trap::NO_TRAP;
1026 if(mem_err_detector)
1027 trapNumber = mem_err_detector->L2CacheFill(memXact);
1028
1029 // If NotData
1030 if (trapNumber != SS_Trap::NO_TRAP)
1031 {
1032 // flip all the parity bits
1033 uint32_t parity = calc_dcache_parity(dcacheDiagDataLdAddr);
1034 parity ^= 0xff;
1035 dcacheDiagDataLdAddr.data_notparity(0);
1036
1037 N2_DcacheDataStReg dcacheDataStReg;
1038 dcacheDataStReg.set(parity);
1039 dcacheData[dcacheDiagDataLdAddr()] = dcacheDataStReg;
1040 if (errortype == 0)
1041 {
1042 return trapNumber;
1043 }
1044 }
1045 }
1046 }
1047
1048 if (errortype)
1049 { // errtype != 0
1050
1051 if (desr.f() == 0)
1052 {
1053 uint32_t errorAddr = index;
1054 if (hit_way != -1) {
1055 errorAddr |= hit_way << N2_DcacheAddressingFields::bit_size_sets;
1056 }
1057 desr.erraddr(errorAddr);
1058 }
1059
1060 // invalidate all ways
1061 for (uint32_t way = 0; way < N2_DcacheAddressingFields::DCACHE_WAYS; ++way)
1062 {
1063 N2_DcacheDiagTagAddrFields dcacheDiagTagAddr;
1064 dcacheDiagTagAddr.way(way);
1065 dcacheDiagTagAddr.index(index);
1066 dcacheTag.erase(dcacheDiagTagAddr());
1067
1068 for (int dword = 0; dword < (1<<N2_DcacheDiagDataLdAddrFields::bit_size_doubleword); dword++)
1069 {
1070 N2_DcacheDiagDataLdAddrFields dcacheDiagDataLdAddr;
1071 dcacheDiagDataLdAddr.way(way);
1072 dcacheDiagDataLdAddr.index(index);
1073 dcacheDiagDataLdAddr.doubleword(dword);
1074 dcacheData.erase(dcacheDiagDataLdAddr());
1075
1076 dcacheDiagDataLdAddr.data_notparity(1);
1077 dcacheData.erase(dcacheDiagDataLdAddr());
1078 dcacheDiagDataLdAddr.data_notparity(0);
1079 }
1080 }
1081
1082 if (desr.f() == 0)
1083 {
1084 desr.f(1);
1085 desr.s(0);
1086 desr.errtype(errortype);
1087 update_clesr(strand_id, 1, desr.f());
1088 } else
1089 {
1090 desr.me(1);
1091 }
1092 if (trap_enabled)
1093 {
1094 return SS_Trap::HW_CORRECTED_ERROR;
1095 }
1096 }
1097 return SS_Trap::NO_TRAP;
1098}
1099/*}}}*/
1100
1101// flushDcache() flushes the D-cache line at paddr.
1102//
1103// No RAS correction or detection occurs.
1104
1105void N2_Core::flush_dcache(uint64_t paddr)/*{{{*/
1106{
1107 if (dcache_empty) // avoid searching #$ if empty
1108 return;
1109
1110 N2_DcacheAddressingFields pc_pa;
1111 pc_pa.set(paddr);
1112
1113 // Verify correct alignment
1114 /*if (paddr % (1 << N2_DcacheAddressingFields::bitSizeDATA)) {
1115 RS_DOMAIN_ERR("N2_core::flushDcache(): misaligned paddr 0x%ullx",
1116 paddr);
1117 }*/
1118
1119 // Look for a matching line in the cache and invalidate it
1120 int32_t hit_way;
1121 search_dcache_tags(pc_pa, hit_way);
1122
1123 if (hit_way != -1)
1124 {
1125 N2_DcacheTagLdReg dcacheTagLdReg;
1126 dcacheTagLdReg.valid1(0);
1127 dcacheTagLdReg.valid0(0);
1128
1129 N2_DcacheDiagTagAddrFields diagTagAddr;
1130 diagTagAddr.index(pc_pa.sets());
1131 diagTagAddr.way(hit_way);
1132
1133 // write the tag into the cache
1134 dcacheTag[diagTagAddr()] = dcacheTagLdReg;
1135 }
1136}
1137/*}}}*/
1138
1139// searchDcacheTags() returns the RAS error type found in Tbl. 12-13,
1140// N2 1.1 PRM. It is passed the physical address to be looked up and
1141// a reference to the matching way if the address hits in the D-cache.
1142// If there is no hit, the reference is set to -1.
1143
1144uint32_t N2_Core::search_dcache_tags(N2_DcacheAddressingFields pa,int32_t &hit_way)/*{{{*/
1145{
1146 // Dcache has 16 byte lines, with four ways
1147
1148 uint64_t index = pa.sets();
1149 uint64_t tag = pa.tag();
1150 uint64_t dw = pa.data();
1151 uint64_t way;
1152 char valids[N2_DcacheAddressingFields::DCACHE_WAYS];
1153 char perrs[N2_DcacheAddressingFields::DCACHE_WAYS];
1154 uint64_t tags[N2_DcacheAddressingFields::DCACHE_WAYS];
1155
1156 hit_way = -1;
1157
1158 /* Search all the ways for tag valids and tag valid errors */
1159
1160 for (way = 0; way < N2_DcacheAddressingFields::DCACHE_WAYS; way++)
1161 {
1162 N2_DcacheDiagTagAddrFields dcacheDiagTagAddr;
1163 dcacheDiagTagAddr.way(way);
1164 dcacheDiagTagAddr.index(index);
1165
1166 N2_DcacheTagLdReg dcacheTagLdReg = dcacheTag[dcacheDiagTagAddr()];
1167
1168 // check valids
1169 if (dcacheTagLdReg.valid1() != dcacheTagLdReg.valid0())
1170 {
1171 if (cerer.dcvp())
1172 {
1173 hit_way = way;
1174 return 5;
1175 }
1176 }
1177
1178 valids[way] = dcacheTagLdReg.valid0();
1179 tags[way] = dcacheTagLdReg.tag();
1180
1181 uint64_t pe;
1182 pe = BL_BitUtility::calc_parity(tags[way]);
1183 pe ^= dcacheTagLdReg.tag_parity();
1184 perrs[way] = pe;
1185 }
1186
1187 // next highest priority is D-cache Tag parity
1188
1189 for (way = 0; way < N2_DcacheAddressingFields::DCACHE_WAYS; way++)
1190 {
1191 if (valids[way] && perrs[way])
1192 {
1193 if (cerer.dctp())
1194 {
1195 hit_way = way;
1196 return 6;
1197 }
1198 }
1199 }
1200
1201 // next highest priority is d-cache tag multihit
1202
1203 for (way = 0; way < N2_DcacheAddressingFields::DCACHE_WAYS; way++)
1204 {
1205 if (valids[way] && tag == tags[way])
1206 {
1207 if (hit_way != -1 && cerer.dctm())
1208 {
1209 return 7;
1210 }
1211 hit_way = way;
1212 }
1213 }
1214
1215 return 0;
1216}
1217/*}}}*/
1218
1219// Calculates the eight parity bits for the Dcache line at
1220// dcacheDiagDataLdAddr located with diagnostic access
1221
1222uint32_t N2_Core::calc_dcache_parity(N2_DcacheDiagDataLdAddrFields dcacheDiagDataLdAddr)/*{{{*/
1223{
1224 // just to make sure
1225 dcacheDiagDataLdAddr.data_notparity(1);
1226 N2_DcacheDataStReg dcacheDataStReg = dcacheData[dcacheDiagDataLdAddr()];
1227 uint64_t data = dcacheDataStReg.data();
1228
1229 return BL_BitUtility::calc_byte_parities(data);
1230}
1231
1232/*}}}*/
1233
1234// Flush all the decode caches associated with this core.
1235void N2_Core::flush_tte_all()/*{{{*/
1236{
1237 for (uint_t strand_ndx = 0; strand_ndx < N2_Model::NO_STRANDS_PER_CORE;
1238 ++strand_ndx)
1239 strand[strand_ndx]->flush_tte_all();
1240}
1241/*}}}*/