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