Merge zizzer:bk/m5 into isabel.reinhardt.house:/z/stever/ser/m5
[gem5.git] / arch / alpha / alpha_memory.cc
1 /*
2 * Copyright (c) 2003 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sstream>
30 #include <string>
31 #include <vector>
32
33 #include "base/inifile.hh"
34 #include "base/str.hh"
35 #include "base/trace.hh"
36 #include "cpu/exec_context.hh"
37 #include "sim/builder.hh"
38 #include "targetarch/alpha_memory.hh"
39 #include "targetarch/ev5.hh"
40
41 using namespace std;
42
43 ///////////////////////////////////////////////////////////////////////
44 //
45 // Alpha TLB
46 //
47 AlphaTlb::AlphaTlb(const string &name, int s)
48 : SimObject(name), size(s), nlu(0)
49 {
50 table = new AlphaISA::PTE[size];
51 memset(table, 0, sizeof(AlphaISA::PTE[size]));
52 }
53
54 AlphaTlb::~AlphaTlb()
55 {
56 if (table)
57 delete [] table;
58 }
59
60 // look up an entry in the TLB
61 AlphaISA::PTE *
62 AlphaTlb::lookup(Addr vpn, uint8_t asn) const
63 {
64 DPRINTF(TLB, "lookup %#x\n", vpn);
65
66 PageTable::const_iterator i = lookupTable.find(vpn);
67 if (i == lookupTable.end())
68 return NULL;
69
70 while (i->first == vpn) {
71 int index = i->second;
72 AlphaISA::PTE *pte = &table[index];
73 assert(pte->valid);
74 if (vpn == pte->tag && (pte->asma || pte->asn == asn))
75 return pte;
76
77 ++i;
78 }
79
80 // not found...
81 return NULL;
82 }
83
84
85 void
86 AlphaTlb::checkCacheability(MemReqPtr req)
87 {
88 // in Alpha, cacheability is controlled by upper-level bits of the
89 // physical address
90 if (req->paddr & PA_UNCACHED_BIT) {
91 if (PA_IPR_SPACE(req->paddr)) {
92 // IPR memory space not implemented
93 if (!req->xc->misspeculating())
94 panic("IPR memory space not implemented! PA=%x\n", req->paddr);
95 } else {
96 // mark request as uncacheable
97 req->flags |= UNCACHEABLE;
98 }
99 }
100 }
101
102
103 // insert a new TLB entry
104 void
105 AlphaTlb::insert(Addr vaddr, AlphaISA::PTE &pte)
106 {
107 if (table[nlu].valid) {
108 Addr oldvpn = table[nlu].tag;
109 PageTable::iterator i = lookupTable.find(oldvpn);
110
111 if (i == lookupTable.end())
112 panic("TLB entry not found in lookupTable");
113
114 int index;
115 while ((index = i->second) != nlu) {
116 if (table[index].tag != oldvpn)
117 panic("TLB entry not found in lookupTable");
118
119 ++i;
120 }
121
122 DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn);
123
124 lookupTable.erase(i);
125 }
126
127 Addr vpn = VA_VPN(vaddr);
128 DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vpn, pte.ppn);
129
130 table[nlu] = pte;
131 table[nlu].tag = vpn;
132 table[nlu].valid = true;
133
134 lookupTable.insert(make_pair(vpn, nlu));
135 nextnlu();
136 }
137
138 void
139 AlphaTlb::flushAll()
140 {
141 memset(table, 0, sizeof(AlphaISA::PTE[size]));
142 lookupTable.clear();
143 nlu = 0;
144 }
145
146 void
147 AlphaTlb::flushProcesses()
148 {
149 PageTable::iterator i = lookupTable.begin();
150 PageTable::iterator end = lookupTable.end();
151 while (i != end) {
152 int index = i->second;
153 AlphaISA::PTE *pte = &table[index];
154 assert(pte->valid);
155
156 if (!pte->asma) {
157 DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn);
158 pte->valid = false;
159 lookupTable.erase(i);
160 }
161
162 ++i;
163 }
164 }
165
166 void
167 AlphaTlb::flushAddr(Addr vaddr, uint8_t asn)
168 {
169 Addr vpn = VA_VPN(vaddr);
170
171 PageTable::iterator i = lookupTable.find(vpn);
172 if (i == lookupTable.end())
173 return;
174
175 while (i->first == vpn) {
176 int index = i->second;
177 AlphaISA::PTE *pte = &table[index];
178 assert(pte->valid);
179
180 if (vpn == pte->tag && (pte->asma || pte->asn == asn)) {
181 DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vpn, pte->ppn);
182
183 // invalidate this entry
184 pte->valid = false;
185
186 lookupTable.erase(i);
187 }
188
189 ++i;
190 }
191 }
192
193
194 void
195 AlphaTlb::serialize(ostream &os)
196 {
197 SERIALIZE_MEMBER(size);
198 SERIALIZE_MEMBER(nlu);
199
200 // should just add serialize/unserialize methods to AlphaPTE
201 #if 0
202 stringstream buf;
203 for (int i = 0; i < size; i++) {
204 buf.str("");
205 ccprintf(buf, "pte%02d.valid", i);
206 paramOut(buf.str(), table[i].valid);
207
208 buf.str("");
209 ccprintf(buf, "pte%02d.tag", i);
210 paramOut(buf.str(), table[i].tag);
211
212 buf.str("");
213 ccprintf(buf, "pte%02d.ppn", i);
214 paramOut(buf.str(), table[i].ppn);
215
216 buf.str("");
217 ccprintf(buf, "pte%02d.xre", i);
218 paramOut(buf.str(), table[i].xre);
219
220 buf.str("");
221 ccprintf(buf, "pte%02d.xwe", i);
222 paramOut(buf.str(), table[i].xwe);
223
224 buf.str("");
225 ccprintf(buf, "pte%02d.fonr", i);
226 paramOut(buf.str(), table[i].fonr);
227
228 buf.str("");
229 ccprintf(buf, "pte%02d.fonw", i);
230 paramOut(buf.str(), table[i].fonw);
231
232 buf.str("");
233 ccprintf(buf, "pte%02d.asma", i);
234 paramOut(buf.str(), table[i].asma);
235
236 buf.str("");
237 ccprintf(buf, "pte%02d.asn", i);
238 paramOut(buf.str(), table[i].asn);
239 }
240 #endif
241 }
242
243 void
244 AlphaTlb::unserialize(IniFile &db, const string &section)
245 {
246 UNSERIALIZE_MEMBER(size);
247 UNSERIALIZE_MEMBER(nlu);
248
249 #if 0
250 string data;
251 stringstream buf;
252 for (int i = 0; i < size; i++) {
253 buf.str("");
254 ccprintf(buf, "pte%02d.valid", i);
255 db.findDefault(category, buf.str(), data);
256 to_number(data, table[i].valid);
257
258 buf.str("");
259 ccprintf(buf, "pte%02d.tag", i);
260 db.findDefault(category, buf.str(), data);
261 to_number(data, table[i].tag);
262
263 buf.str("");
264 ccprintf(buf, "pte%02d.ppn", i);
265 db.findDefault(category, buf.str(), data);
266 to_number(data, table[i].ppn);
267
268 buf.str("");
269 ccprintf(buf, "pte%02d.xre", i);
270 db.findDefault(category, buf.str(), data);
271 to_number(data, table[i].xre);
272
273 buf.str("");
274 ccprintf(buf, "pte%02d.xwe", i);
275 db.findDefault(category, buf.str(), data);
276 to_number(data, table[i].xwe);
277
278 buf.str("");
279 ccprintf(buf, "pte%02d.fonr", i);
280 db.findDefault(category, buf.str(), data);
281 to_number(data, table[i].fonr);
282
283 buf.str("");
284 ccprintf(buf, "pte%02d.fonw", i);
285 db.findDefault(category, buf.str(), data);
286 to_number(data, table[i].fonw);
287
288 buf.str("");
289 ccprintf(buf, "pte%02d.asma", i);
290 db.findDefault(category, buf.str(), data);
291 to_number(data, table[i].asma);
292
293 buf.str("");
294 ccprintf(buf, "pte%02d.asn", i);
295 db.findDefault(category, buf.str(), data);
296 to_number(data, table[i].asn);
297 }
298 #endif
299 }
300
301
302 ///////////////////////////////////////////////////////////////////////
303 //
304 // Alpha ITB
305 //
306 AlphaItb::AlphaItb(const std::string &name, int size)
307 : AlphaTlb(name, size)
308 {}
309
310
311 void
312 AlphaItb::regStats()
313 {
314 hits
315 .name(name() + ".hits")
316 .desc("ITB hits");
317 misses
318 .name(name() + ".misses")
319 .desc("ITB misses");
320 acv
321 .name(name() + ".acv")
322 .desc("ITB acv");
323 accesses
324 .name(name() + ".accesses")
325 .desc("ITB accesses");
326
327 accesses = hits + misses;
328 }
329
330 void
331 AlphaItb::fault(Addr pc, ExecContext *xc) const
332 {
333 uint64_t *ipr = xc->regs.ipr;
334
335 if (!xc->misspeculating()) {
336 ipr[AlphaISA::IPR_ITB_TAG] = pc;
337 ipr[AlphaISA::IPR_IFAULT_VA_FORM] =
338 ipr[AlphaISA::IPR_IVPTBR] | (VA_VPN(pc) << 3);
339 }
340 }
341
342
343 Fault
344 AlphaItb::translate(MemReqPtr req) const
345 {
346 InternalProcReg *ipr = req->xc->regs.ipr;
347
348 if (PC_PAL(req->vaddr)) {
349 // strip off PAL PC marker (lsb is 1)
350 req->paddr = (req->vaddr & ~3) & PA_IMPL_MASK;
351 hits++;
352 return No_Fault;
353 }
354
355 // verify that this is a good virtual address
356 if (!validVirtualAddress(req->vaddr)) {
357 fault(req->vaddr, req->xc);
358 acv++;
359 return Itb_Acv_Fault;
360 }
361
362 // Check for "superpage" mapping: when SP<1> is set, and
363 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
364 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
365 VA_SPACE(req->vaddr) == 2) {
366 // only valid in kernel mode
367 if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) {
368 fault(req->vaddr, req->xc);
369 acv++;
370 return Itb_Acv_Fault;
371 }
372
373 req->flags |= PHYSICAL;
374 }
375
376 if (req->flags & PHYSICAL) {
377 req->paddr = req->vaddr & PA_IMPL_MASK;
378 } else {
379 // not a physical address: need to look up pte
380
381 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
382 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
383
384 if (!pte) {
385 fault(req->vaddr, req->xc);
386 misses++;
387 return Itb_Fault_Fault;
388 }
389
390 req->paddr = PA_PFN2PA(pte->ppn) + VA_POFS(req->vaddr & ~3);
391
392 // check permissions for this access
393 if (!(pte->xre & (1 << ICM_CM(ipr[AlphaISA::IPR_ICM])))) {
394 // instruction access fault
395 fault(req->vaddr, req->xc);
396 acv++;
397 return Itb_Acv_Fault;
398 }
399 }
400
401 checkCacheability(req);
402
403 hits++;
404 return No_Fault;
405 }
406
407 ///////////////////////////////////////////////////////////////////////
408 //
409 // Alpha DTB
410 //
411 AlphaDtb::AlphaDtb(const std::string &name, int size)
412 : AlphaTlb(name, size)
413 {}
414
415 void
416 AlphaDtb::regStats()
417 {
418 read_hits
419 .name(name() + ".read_hits")
420 .desc("DTB read hits")
421 ;
422
423 read_misses
424 .name(name() + ".read_misses")
425 .desc("DTB read misses")
426 ;
427
428 read_acv
429 .name(name() + ".read_acv")
430 .desc("DTB read access violations")
431 ;
432
433 read_accesses
434 .name(name() + ".read_accesses")
435 .desc("DTB read accesses")
436 ;
437
438 write_hits
439 .name(name() + ".write_hits")
440 .desc("DTB write hits")
441 ;
442
443 write_misses
444 .name(name() + ".write_misses")
445 .desc("DTB write misses")
446 ;
447
448 write_acv
449 .name(name() + ".write_acv")
450 .desc("DTB write access violations")
451 ;
452
453 write_accesses
454 .name(name() + ".write_accesses")
455 .desc("DTB write accesses")
456 ;
457
458 hits
459 .name(name() + ".hits")
460 .desc("DTB hits")
461 ;
462
463 misses
464 .name(name() + ".misses")
465 .desc("DTB misses")
466 ;
467
468 acv
469 .name(name() + ".acv")
470 .desc("DTB access violations")
471 ;
472
473 accesses
474 .name(name() + ".accesses")
475 .desc("DTB accesses")
476 ;
477
478 hits = read_hits + write_hits;
479 misses = read_misses + write_misses;
480 acv = read_acv + write_acv;
481 accesses = read_accesses + write_accesses;
482 }
483
484 void
485 AlphaDtb::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const
486 {
487 uint64_t *ipr = xc->regs.ipr;
488
489 // set fault address and flags
490 if (!xc->misspeculating() && !xc->regs.intrlock) {
491 // set VA register with faulting address
492 ipr[AlphaISA::IPR_VA] = vaddr;
493
494 // set MM_STAT register flags
495 ipr[AlphaISA::IPR_MM_STAT] = (((xc->regs.opcode & 0x3f) << 11)
496 | ((xc->regs.ra & 0x1f) << 6)
497 | (flags & 0x3f));
498
499 // set VA_FORM register with faulting formatted address
500 ipr[AlphaISA::IPR_VA_FORM] =
501 ipr[AlphaISA::IPR_MVPTBR] | (VA_VPN(vaddr) << 3);
502
503 // lock these registers until the VA register is read
504 xc->regs.intrlock = true;
505 }
506 }
507
508 Fault
509 AlphaDtb::translate(MemReqPtr req, bool write) const
510 {
511 RegFile *regs = &req->xc->regs;
512 Addr pc = regs->pc;
513 InternalProcReg *ipr = regs->ipr;
514
515 if (write)
516 write_accesses++;
517 else
518 read_accesses++;
519
520 AlphaISA::md_mode_type mode =
521 (AlphaISA::md_mode_type)DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]);
522
523 if (PC_PAL(pc)) {
524 mode = (req->flags & ALTMODE) ? (AlphaISA::md_mode_type)
525 (ALT_MODE_AM(ipr[AlphaISA::IPR_ALT_MODE]))
526 : AlphaISA::mode_kernel;
527 }
528
529 // verify that this is a good virtual address
530 if (!validVirtualAddress(req->vaddr)) {
531 fault(req->vaddr,
532 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_BAD_VA_MASK |
533 MM_STAT_ACV_MASK),
534 req->xc);
535
536 if (write) { write_acv++; } else { read_acv++; }
537 return Dtb_Fault_Fault;
538 }
539
540 // Check for "superpage" mapping: when SP<1> is set, and
541 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
542 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && VA_SPACE(req->vaddr) == 2) {
543 // only valid in kernel mode
544 if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) != AlphaISA::mode_kernel) {
545 fault(req->vaddr,
546 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK),
547 req->xc);
548 if (write) { write_acv++; } else { read_acv++; }
549 return Dtb_Acv_Fault;
550 }
551
552 req->flags |= PHYSICAL;
553 }
554
555 if (req->flags & PHYSICAL) {
556 req->paddr = req->vaddr & PA_IMPL_MASK;
557 } else {
558 // not a physical address: need to look up pte
559
560 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
561 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
562
563 if (!pte) {
564 // page fault
565 fault(req->vaddr,
566 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK),
567 req->xc);
568 if (write) { write_misses++; } else { read_misses++; }
569 return (req->flags & VPTE) ? Pdtb_Miss_Fault : Ndtb_Miss_Fault;
570 }
571
572 req->paddr = PA_PFN2PA(pte->ppn) | VA_POFS(req->vaddr);
573
574 if (write) {
575 if (!(pte->xwe & MODE2MASK(mode))) {
576 // declare the instruction access fault
577 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_ACV_MASK |
578 (pte->fonw ? MM_STAT_FONW_MASK : 0),
579 req->xc);
580 write_acv++;
581 return Dtb_Fault_Fault;
582 }
583 if (pte->fonw) {
584 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_FONW_MASK,
585 req->xc);
586 write_acv++;
587 return Dtb_Fault_Fault;
588 }
589 } else {
590 if (!(pte->xre & MODE2MASK(mode))) {
591 fault(req->vaddr,
592 MM_STAT_ACV_MASK | (pte->fonr ? MM_STAT_FONR_MASK : 0),
593 req->xc);
594 read_acv++;
595 return Dtb_Acv_Fault;
596 }
597 if (pte->fonr) {
598 fault(req->vaddr, MM_STAT_FONR_MASK, req->xc);
599 read_acv++;
600 return Dtb_Fault_Fault;
601 }
602 }
603 }
604
605 checkCacheability(req);
606
607 if (write)
608 write_hits++;
609 else
610 read_hits++;
611
612 return No_Fault;
613 }
614
615 AlphaISA::PTE &
616 AlphaTlb::index()
617 {
618 AlphaISA::PTE *pte = &table[nlu];
619 nextnlu();
620
621 return *pte;
622 }
623
624 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaItb)
625
626 Param<int> size;
627
628 END_DECLARE_SIM_OBJECT_PARAMS(AlphaItb)
629
630 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaItb)
631
632 INIT_PARAM_DFLT(size, "TLB size", 48)
633
634 END_INIT_SIM_OBJECT_PARAMS(AlphaItb)
635
636
637 CREATE_SIM_OBJECT(AlphaItb)
638 {
639 return new AlphaItb(getInstanceName(), size);
640 }
641
642 REGISTER_SIM_OBJECT("AlphaITB", AlphaItb)
643
644 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb)
645
646 Param<int> size;
647
648 END_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb)
649
650 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDtb)
651
652 INIT_PARAM_DFLT(size, "TLB size", 64)
653
654 END_INIT_SIM_OBJECT_PARAMS(AlphaDtb)
655
656
657 CREATE_SIM_OBJECT(AlphaDtb)
658 {
659 return new AlphaDtb(getInstanceName(), size);
660 }
661
662 REGISTER_SIM_OBJECT("AlphaDTB", AlphaDtb)
663