Added ULL for 64bit ints
[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
48 #ifdef DEBUG
49 bool uncacheBit39 = false;
50 bool uncacheBit40 = false;
51 #endif
52
53 AlphaTlb::AlphaTlb(const string &name, int s)
54 : SimObject(name), size(s), nlu(0)
55 {
56 table = new AlphaISA::PTE[size];
57 memset(table, 0, sizeof(AlphaISA::PTE[size]));
58 }
59
60 AlphaTlb::~AlphaTlb()
61 {
62 if (table)
63 delete [] table;
64 }
65
66 // look up an entry in the TLB
67 AlphaISA::PTE *
68 AlphaTlb::lookup(Addr vpn, uint8_t asn) const
69 {
70 DPRINTF(TLB, "lookup %#x\n", vpn);
71
72 PageTable::const_iterator i = lookupTable.find(vpn);
73 if (i == lookupTable.end())
74 return NULL;
75
76 while (i->first == vpn) {
77 int index = i->second;
78 AlphaISA::PTE *pte = &table[index];
79 assert(pte->valid);
80 if (vpn == pte->tag && (pte->asma || pte->asn == asn))
81 return pte;
82
83 ++i;
84 }
85
86 // not found...
87 return NULL;
88 }
89
90
91 void
92 AlphaTlb::checkCacheability(MemReqPtr &req)
93 {
94 // in Alpha, cacheability is controlled by upper-level bits of the
95 // physical address
96
97 /*
98 * We support having the uncacheable bit in either bit 39 or bit 40.
99 * The Turbolaser platform (and EV5) support having the bit in 39, but
100 * Tsunami (which Linux assumes uses an EV6) generates accesses with
101 * the bit in 40. So we must check for both, but we have debug flags
102 * to catch a weird case where both are used, which shouldn't happen.
103 */
104
105 if (req->paddr & PA_UNCACHED_BIT_40 ||
106 req->paddr & PA_UNCACHED_BIT_39) {
107
108 #ifdef DEBUG
109 if (req->paddr & PA_UNCACHED_BIT_40) {
110 if(uncacheBit39)
111 panic("Bit 40 access follows bit 39 access, PA=%x\n",
112 req->paddr);
113
114 uncacheBit40 = true;
115 } else if (req->paddr & PA_UNCACHED_BIT_39) {
116 if(uncacheBit40)
117 panic("Bit 39 acceess follows bit 40 access, PA=%x\n",
118 req->paddr);
119
120 uncacheBit39 = true;
121 }
122 #endif
123
124 // IPR memory space not implemented
125 if (PA_IPR_SPACE(req->paddr))
126 if (!req->xc->misspeculating())
127 panic("IPR memory space not implemented! PA=%x\n",
128 req->paddr);
129
130 // mark request as uncacheable
131 req->flags |= UNCACHEABLE;
132 }
133 }
134
135
136 // insert a new TLB entry
137 void
138 AlphaTlb::insert(Addr vaddr, AlphaISA::PTE &pte)
139 {
140 if (table[nlu].valid) {
141 Addr oldvpn = table[nlu].tag;
142 PageTable::iterator i = lookupTable.find(oldvpn);
143
144 if (i == lookupTable.end())
145 panic("TLB entry not found in lookupTable");
146
147 int index;
148 while ((index = i->second) != nlu) {
149 if (table[index].tag != oldvpn)
150 panic("TLB entry not found in lookupTable");
151
152 ++i;
153 }
154
155 DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn);
156
157 lookupTable.erase(i);
158 }
159
160 Addr vpn = VA_VPN(vaddr);
161 DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vpn, pte.ppn);
162
163 table[nlu] = pte;
164 table[nlu].tag = vpn;
165 table[nlu].valid = true;
166
167 lookupTable.insert(make_pair(vpn, nlu));
168 nextnlu();
169 }
170
171 void
172 AlphaTlb::flushAll()
173 {
174 memset(table, 0, sizeof(AlphaISA::PTE[size]));
175 lookupTable.clear();
176 nlu = 0;
177 }
178
179 void
180 AlphaTlb::flushProcesses()
181 {
182 PageTable::iterator i = lookupTable.begin();
183 PageTable::iterator end = lookupTable.end();
184 while (i != end) {
185 int index = i->second;
186 AlphaISA::PTE *pte = &table[index];
187 assert(pte->valid);
188
189 if (!pte->asma) {
190 DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn);
191 pte->valid = false;
192 lookupTable.erase(i);
193 }
194
195 ++i;
196 }
197 }
198
199 void
200 AlphaTlb::flushAddr(Addr vaddr, uint8_t asn)
201 {
202 Addr vpn = VA_VPN(vaddr);
203
204 PageTable::iterator i = lookupTable.find(vpn);
205 if (i == lookupTable.end())
206 return;
207
208 while (i->first == vpn) {
209 int index = i->second;
210 AlphaISA::PTE *pte = &table[index];
211 assert(pte->valid);
212
213 if (vpn == pte->tag && (pte->asma || pte->asn == asn)) {
214 DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vpn, pte->ppn);
215
216 // invalidate this entry
217 pte->valid = false;
218
219 lookupTable.erase(i);
220 }
221
222 ++i;
223 }
224 }
225
226
227 void
228 AlphaTlb::serialize(ostream &os)
229 {
230 SERIALIZE_SCALAR(size);
231 SERIALIZE_SCALAR(nlu);
232
233 for (int i = 0; i < size; i++) {
234 nameOut(os, csprintf("%s.PTE%d", name(), i));
235 table[i].serialize(os);
236 }
237 }
238
239 void
240 AlphaTlb::unserialize(Checkpoint *cp, const string &section)
241 {
242 UNSERIALIZE_SCALAR(size);
243 UNSERIALIZE_SCALAR(nlu);
244
245 for (int i = 0; i < size; i++) {
246 table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
247 if (table[i].valid) {
248 lookupTable.insert(make_pair(table[i].tag, i));
249 }
250 }
251 }
252
253
254 ///////////////////////////////////////////////////////////////////////
255 //
256 // Alpha ITB
257 //
258 AlphaItb::AlphaItb(const std::string &name, int size)
259 : AlphaTlb(name, size)
260 {}
261
262
263 void
264 AlphaItb::regStats()
265 {
266 hits
267 .name(name() + ".hits")
268 .desc("ITB hits");
269 misses
270 .name(name() + ".misses")
271 .desc("ITB misses");
272 acv
273 .name(name() + ".acv")
274 .desc("ITB acv");
275 accesses
276 .name(name() + ".accesses")
277 .desc("ITB accesses");
278
279 accesses = hits + misses;
280 }
281
282 void
283 AlphaItb::fault(Addr pc, ExecContext *xc) const
284 {
285 uint64_t *ipr = xc->regs.ipr;
286
287 if (!xc->misspeculating()) {
288 ipr[AlphaISA::IPR_ITB_TAG] = pc;
289 ipr[AlphaISA::IPR_IFAULT_VA_FORM] =
290 ipr[AlphaISA::IPR_IVPTBR] | (VA_VPN(pc) << 3);
291 }
292 }
293
294
295 Fault
296 AlphaItb::translate(MemReqPtr &req) const
297 {
298 InternalProcReg *ipr = req->xc->regs.ipr;
299
300 if (PC_PAL(req->vaddr)) {
301 // strip off PAL PC marker (lsb is 1)
302 req->paddr = (req->vaddr & ~3) & PA_IMPL_MASK;
303 hits++;
304 return No_Fault;
305 }
306
307 if (req->flags & PHYSICAL) {
308 req->paddr = req->vaddr;
309 } else {
310 // verify that this is a good virtual address
311 if (!validVirtualAddress(req->vaddr)) {
312 fault(req->vaddr, req->xc);
313 acv++;
314 return Itb_Acv_Fault;
315 }
316
317 // Check for "superpage" mapping: when SP<1> is set, and
318 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
319 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
320 VA_SPACE(req->vaddr) == 2) {
321
322 // only valid in kernel mode
323 if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) {
324 fault(req->vaddr, req->xc);
325 acv++;
326 return Itb_Acv_Fault;
327 }
328
329 req->paddr = req->vaddr & PA_IMPL_MASK;
330
331 // sign extend the physical address properly
332 if (req->paddr & PA_UNCACHED_BIT_39 ||
333 req->paddr & PA_UNCACHED_BIT_40)
334 req->paddr |= 0xf0000000000ULL;
335 else
336 req->paddr &= 0xffffffffffULL;
337
338 } else {
339 // not a physical address: need to look up pte
340 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
341 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
342
343 if (!pte) {
344 fault(req->vaddr, req->xc);
345 misses++;
346 return Itb_Fault_Fault;
347 }
348
349 req->paddr = PA_PFN2PA(pte->ppn) + VA_POFS(req->vaddr & ~3);
350
351 // check permissions for this access
352 if (!(pte->xre & (1 << ICM_CM(ipr[AlphaISA::IPR_ICM])))) {
353 // instruction access fault
354 fault(req->vaddr, req->xc);
355 acv++;
356 return Itb_Acv_Fault;
357 }
358
359 hits++;
360 }
361 }
362
363 // check that the physical address is ok (catch bad physical addresses)
364 if (req->paddr & ~PA_IMPL_MASK)
365 return Machine_Check_Fault;
366
367 checkCacheability(req);
368
369 return No_Fault;
370 }
371
372 ///////////////////////////////////////////////////////////////////////
373 //
374 // Alpha DTB
375 //
376 AlphaDtb::AlphaDtb(const std::string &name, int size)
377 : AlphaTlb(name, size)
378 {}
379
380 void
381 AlphaDtb::regStats()
382 {
383 read_hits
384 .name(name() + ".read_hits")
385 .desc("DTB read hits")
386 ;
387
388 read_misses
389 .name(name() + ".read_misses")
390 .desc("DTB read misses")
391 ;
392
393 read_acv
394 .name(name() + ".read_acv")
395 .desc("DTB read access violations")
396 ;
397
398 read_accesses
399 .name(name() + ".read_accesses")
400 .desc("DTB read accesses")
401 ;
402
403 write_hits
404 .name(name() + ".write_hits")
405 .desc("DTB write hits")
406 ;
407
408 write_misses
409 .name(name() + ".write_misses")
410 .desc("DTB write misses")
411 ;
412
413 write_acv
414 .name(name() + ".write_acv")
415 .desc("DTB write access violations")
416 ;
417
418 write_accesses
419 .name(name() + ".write_accesses")
420 .desc("DTB write accesses")
421 ;
422
423 hits
424 .name(name() + ".hits")
425 .desc("DTB hits")
426 ;
427
428 misses
429 .name(name() + ".misses")
430 .desc("DTB misses")
431 ;
432
433 acv
434 .name(name() + ".acv")
435 .desc("DTB access violations")
436 ;
437
438 accesses
439 .name(name() + ".accesses")
440 .desc("DTB accesses")
441 ;
442
443 hits = read_hits + write_hits;
444 misses = read_misses + write_misses;
445 acv = read_acv + write_acv;
446 accesses = read_accesses + write_accesses;
447 }
448
449 void
450 AlphaDtb::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const
451 {
452 uint64_t *ipr = xc->regs.ipr;
453
454 // set fault address and flags
455 if (!xc->misspeculating() && !xc->regs.intrlock) {
456 // set VA register with faulting address
457 ipr[AlphaISA::IPR_VA] = vaddr;
458
459 // set MM_STAT register flags
460 ipr[AlphaISA::IPR_MM_STAT] = (((xc->regs.opcode & 0x3f) << 11)
461 | ((xc->regs.ra & 0x1f) << 6)
462 | (flags & 0x3f));
463
464 // set VA_FORM register with faulting formatted address
465 ipr[AlphaISA::IPR_VA_FORM] =
466 ipr[AlphaISA::IPR_MVPTBR] | (VA_VPN(vaddr) << 3);
467
468 // lock these registers until the VA register is read
469 xc->regs.intrlock = true;
470 }
471 }
472
473 Fault
474 AlphaDtb::translate(MemReqPtr &req, bool write) const
475 {
476 RegFile *regs = &req->xc->regs;
477 Addr pc = regs->pc;
478 InternalProcReg *ipr = regs->ipr;
479
480 AlphaISA::mode_type mode =
481 (AlphaISA::mode_type)DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]);
482
483 if (PC_PAL(pc)) {
484 mode = (req->flags & ALTMODE) ?
485 (AlphaISA::mode_type)ALT_MODE_AM(ipr[AlphaISA::IPR_ALT_MODE])
486 : AlphaISA::mode_kernel;
487 }
488
489 if (req->flags & PHYSICAL) {
490 req->paddr = req->vaddr;
491 } else {
492 // verify that this is a good virtual address
493 if (!validVirtualAddress(req->vaddr)) {
494 fault(req->vaddr,
495 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_BAD_VA_MASK |
496 MM_STAT_ACV_MASK),
497 req->xc);
498
499 if (write) { write_acv++; } else { read_acv++; }
500 return Dtb_Fault_Fault;
501 }
502
503 // Check for "superpage" mapping: when SP<1> is set, and
504 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
505 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
506 VA_SPACE(req->vaddr) == 2) {
507
508 // only valid in kernel mode
509 if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) !=
510 AlphaISA::mode_kernel) {
511 fault(req->vaddr,
512 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK),
513 req->xc);
514 if (write) { write_acv++; } else { read_acv++; }
515 return Dtb_Acv_Fault;
516 }
517
518 req->paddr = req->vaddr & PA_IMPL_MASK;
519
520 // sign extend the physical address properly
521 if (req->paddr & PA_UNCACHED_BIT_39 ||
522 req->paddr & PA_UNCACHED_BIT_40)
523 req->paddr |= 0xf0000000000ULL;
524 else
525 req->paddr &= 0xffffffffffULL;
526
527 } else {
528 if (write)
529 write_accesses++;
530 else
531 read_accesses++;
532
533 // not a physical address: need to look up pte
534 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
535 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
536
537 if (!pte) {
538 // page fault
539 fault(req->vaddr,
540 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK),
541 req->xc);
542 if (write) { write_misses++; } else { read_misses++; }
543 return (req->flags & VPTE) ? Pdtb_Miss_Fault : Ndtb_Miss_Fault;
544 }
545
546 req->paddr = PA_PFN2PA(pte->ppn) | VA_POFS(req->vaddr);
547
548 if (write) {
549 if (!(pte->xwe & MODE2MASK(mode))) {
550 // declare the instruction access fault
551 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_ACV_MASK |
552 (pte->fonw ? MM_STAT_FONW_MASK : 0),
553 req->xc);
554 write_acv++;
555 return Dtb_Fault_Fault;
556 }
557 if (pte->fonw) {
558 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_FONW_MASK,
559 req->xc);
560 write_acv++;
561 return Dtb_Fault_Fault;
562 }
563 } else {
564 if (!(pte->xre & MODE2MASK(mode))) {
565 fault(req->vaddr,
566 MM_STAT_ACV_MASK |
567 (pte->fonr ? MM_STAT_FONR_MASK : 0),
568 req->xc);
569 read_acv++;
570 return Dtb_Acv_Fault;
571 }
572 if (pte->fonr) {
573 fault(req->vaddr, MM_STAT_FONR_MASK, req->xc);
574 read_acv++;
575 return Dtb_Fault_Fault;
576 }
577 }
578 }
579
580 if (write)
581 write_hits++;
582 else
583 read_hits++;
584 }
585
586 // check that the physical address is ok (catch bad physical addresses)
587 if (req->paddr & ~PA_IMPL_MASK)
588 return Machine_Check_Fault;
589
590 checkCacheability(req);
591
592 return No_Fault;
593 }
594
595 AlphaISA::PTE &
596 AlphaTlb::index(bool advance)
597 {
598 AlphaISA::PTE *pte = &table[nlu];
599
600 if (advance)
601 nextnlu();
602
603 return *pte;
604 }
605
606 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaItb)
607
608 Param<int> size;
609
610 END_DECLARE_SIM_OBJECT_PARAMS(AlphaItb)
611
612 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaItb)
613
614 INIT_PARAM_DFLT(size, "TLB size", 48)
615
616 END_INIT_SIM_OBJECT_PARAMS(AlphaItb)
617
618
619 CREATE_SIM_OBJECT(AlphaItb)
620 {
621 return new AlphaItb(getInstanceName(), size);
622 }
623
624 REGISTER_SIM_OBJECT("AlphaITB", AlphaItb)
625
626 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb)
627
628 Param<int> size;
629
630 END_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb)
631
632 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDtb)
633
634 INIT_PARAM_DFLT(size, "TLB size", 64)
635
636 END_INIT_SIM_OBJECT_PARAMS(AlphaDtb)
637
638
639 CREATE_SIM_OBJECT(AlphaDtb)
640 {
641 return new AlphaDtb(getInstanceName(), size);
642 }
643
644 REGISTER_SIM_OBJECT("AlphaDTB", AlphaDtb)
645