Merge zizzer:/bk/m5 into isabel.reinhardt.house:/z/stever/bk2/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_SCALAR(size);
198 SERIALIZE_SCALAR(nlu);
199
200 for (int i = 0; i < size; i++) {
201 nameOut(os, csprintf("%s.PTE%d", name(), i));
202 table[i].serialize(os);
203 }
204 }
205
206 void
207 AlphaTlb::unserialize(Checkpoint *cp, const string &section)
208 {
209 UNSERIALIZE_SCALAR(size);
210 UNSERIALIZE_SCALAR(nlu);
211
212 for (int i = 0; i < size; i++) {
213 table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
214 if (table[i].valid) {
215 lookupTable.insert(make_pair(table[i].tag, i));
216 }
217 }
218 }
219
220
221 ///////////////////////////////////////////////////////////////////////
222 //
223 // Alpha ITB
224 //
225 AlphaItb::AlphaItb(const std::string &name, int size)
226 : AlphaTlb(name, size)
227 {}
228
229
230 void
231 AlphaItb::regStats()
232 {
233 hits
234 .name(name() + ".hits")
235 .desc("ITB hits");
236 misses
237 .name(name() + ".misses")
238 .desc("ITB misses");
239 acv
240 .name(name() + ".acv")
241 .desc("ITB acv");
242 accesses
243 .name(name() + ".accesses")
244 .desc("ITB accesses");
245
246 accesses = hits + misses;
247 }
248
249 void
250 AlphaItb::fault(Addr pc, ExecContext *xc) const
251 {
252 uint64_t *ipr = xc->regs.ipr;
253
254 if (!xc->misspeculating()) {
255 ipr[AlphaISA::IPR_ITB_TAG] = pc;
256 ipr[AlphaISA::IPR_IFAULT_VA_FORM] =
257 ipr[AlphaISA::IPR_IVPTBR] | (VA_VPN(pc) << 3);
258 }
259 }
260
261
262 Fault
263 AlphaItb::translate(MemReqPtr req) const
264 {
265 InternalProcReg *ipr = req->xc->regs.ipr;
266
267 if (PC_PAL(req->vaddr)) {
268 // strip off PAL PC marker (lsb is 1)
269 req->paddr = (req->vaddr & ~3) & PA_IMPL_MASK;
270 hits++;
271 return No_Fault;
272 }
273
274 // verify that this is a good virtual address
275 if (!validVirtualAddress(req->vaddr)) {
276 fault(req->vaddr, req->xc);
277 acv++;
278 return Itb_Acv_Fault;
279 }
280
281 // Check for "superpage" mapping: when SP<1> is set, and
282 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
283 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
284 VA_SPACE(req->vaddr) == 2) {
285 // only valid in kernel mode
286 if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) {
287 fault(req->vaddr, req->xc);
288 acv++;
289 return Itb_Acv_Fault;
290 }
291
292 req->flags |= PHYSICAL;
293 }
294
295 if (req->flags & PHYSICAL) {
296 req->paddr = req->vaddr & PA_IMPL_MASK;
297 } else {
298 // not a physical address: need to look up pte
299
300 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
301 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
302
303 if (!pte) {
304 fault(req->vaddr, req->xc);
305 misses++;
306 return Itb_Fault_Fault;
307 }
308
309 req->paddr = PA_PFN2PA(pte->ppn) + VA_POFS(req->vaddr & ~3);
310
311 // check permissions for this access
312 if (!(pte->xre & (1 << ICM_CM(ipr[AlphaISA::IPR_ICM])))) {
313 // instruction access fault
314 fault(req->vaddr, req->xc);
315 acv++;
316 return Itb_Acv_Fault;
317 }
318 }
319
320 checkCacheability(req);
321
322 hits++;
323 return No_Fault;
324 }
325
326 ///////////////////////////////////////////////////////////////////////
327 //
328 // Alpha DTB
329 //
330 AlphaDtb::AlphaDtb(const std::string &name, int size)
331 : AlphaTlb(name, size)
332 {}
333
334 void
335 AlphaDtb::regStats()
336 {
337 read_hits
338 .name(name() + ".read_hits")
339 .desc("DTB read hits")
340 ;
341
342 read_misses
343 .name(name() + ".read_misses")
344 .desc("DTB read misses")
345 ;
346
347 read_acv
348 .name(name() + ".read_acv")
349 .desc("DTB read access violations")
350 ;
351
352 read_accesses
353 .name(name() + ".read_accesses")
354 .desc("DTB read accesses")
355 ;
356
357 write_hits
358 .name(name() + ".write_hits")
359 .desc("DTB write hits")
360 ;
361
362 write_misses
363 .name(name() + ".write_misses")
364 .desc("DTB write misses")
365 ;
366
367 write_acv
368 .name(name() + ".write_acv")
369 .desc("DTB write access violations")
370 ;
371
372 write_accesses
373 .name(name() + ".write_accesses")
374 .desc("DTB write accesses")
375 ;
376
377 hits
378 .name(name() + ".hits")
379 .desc("DTB hits")
380 ;
381
382 misses
383 .name(name() + ".misses")
384 .desc("DTB misses")
385 ;
386
387 acv
388 .name(name() + ".acv")
389 .desc("DTB access violations")
390 ;
391
392 accesses
393 .name(name() + ".accesses")
394 .desc("DTB accesses")
395 ;
396
397 hits = read_hits + write_hits;
398 misses = read_misses + write_misses;
399 acv = read_acv + write_acv;
400 accesses = read_accesses + write_accesses;
401 }
402
403 void
404 AlphaDtb::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const
405 {
406 uint64_t *ipr = xc->regs.ipr;
407
408 // set fault address and flags
409 if (!xc->misspeculating() && !xc->regs.intrlock) {
410 // set VA register with faulting address
411 ipr[AlphaISA::IPR_VA] = vaddr;
412
413 // set MM_STAT register flags
414 ipr[AlphaISA::IPR_MM_STAT] = (((xc->regs.opcode & 0x3f) << 11)
415 | ((xc->regs.ra & 0x1f) << 6)
416 | (flags & 0x3f));
417
418 // set VA_FORM register with faulting formatted address
419 ipr[AlphaISA::IPR_VA_FORM] =
420 ipr[AlphaISA::IPR_MVPTBR] | (VA_VPN(vaddr) << 3);
421
422 // lock these registers until the VA register is read
423 xc->regs.intrlock = true;
424 }
425 }
426
427 Fault
428 AlphaDtb::translate(MemReqPtr req, bool write) const
429 {
430 RegFile *regs = &req->xc->regs;
431 Addr pc = regs->pc;
432 InternalProcReg *ipr = regs->ipr;
433
434 if (write)
435 write_accesses++;
436 else
437 read_accesses++;
438
439 AlphaISA::md_mode_type mode =
440 (AlphaISA::md_mode_type)DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]);
441
442 if (PC_PAL(pc)) {
443 mode = (req->flags & ALTMODE) ? (AlphaISA::md_mode_type)
444 (ALT_MODE_AM(ipr[AlphaISA::IPR_ALT_MODE]))
445 : AlphaISA::mode_kernel;
446 }
447
448 // verify that this is a good virtual address
449 if (!validVirtualAddress(req->vaddr)) {
450 fault(req->vaddr,
451 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_BAD_VA_MASK |
452 MM_STAT_ACV_MASK),
453 req->xc);
454
455 if (write) { write_acv++; } else { read_acv++; }
456 return Dtb_Fault_Fault;
457 }
458
459 // Check for "superpage" mapping: when SP<1> is set, and
460 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
461 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && VA_SPACE(req->vaddr) == 2) {
462 // only valid in kernel mode
463 if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) != AlphaISA::mode_kernel) {
464 fault(req->vaddr,
465 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK),
466 req->xc);
467 if (write) { write_acv++; } else { read_acv++; }
468 return Dtb_Acv_Fault;
469 }
470
471 req->flags |= PHYSICAL;
472 }
473
474 if (req->flags & PHYSICAL) {
475 req->paddr = req->vaddr & PA_IMPL_MASK;
476 } else {
477 // not a physical address: need to look up pte
478
479 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
480 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
481
482 if (!pte) {
483 // page fault
484 fault(req->vaddr,
485 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK),
486 req->xc);
487 if (write) { write_misses++; } else { read_misses++; }
488 return (req->flags & VPTE) ? Pdtb_Miss_Fault : Ndtb_Miss_Fault;
489 }
490
491 req->paddr = PA_PFN2PA(pte->ppn) | VA_POFS(req->vaddr);
492
493 if (write) {
494 if (!(pte->xwe & MODE2MASK(mode))) {
495 // declare the instruction access fault
496 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_ACV_MASK |
497 (pte->fonw ? MM_STAT_FONW_MASK : 0),
498 req->xc);
499 write_acv++;
500 return Dtb_Fault_Fault;
501 }
502 if (pte->fonw) {
503 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_FONW_MASK,
504 req->xc);
505 write_acv++;
506 return Dtb_Fault_Fault;
507 }
508 } else {
509 if (!(pte->xre & MODE2MASK(mode))) {
510 fault(req->vaddr,
511 MM_STAT_ACV_MASK | (pte->fonr ? MM_STAT_FONR_MASK : 0),
512 req->xc);
513 read_acv++;
514 return Dtb_Acv_Fault;
515 }
516 if (pte->fonr) {
517 fault(req->vaddr, MM_STAT_FONR_MASK, req->xc);
518 read_acv++;
519 return Dtb_Fault_Fault;
520 }
521 }
522 }
523
524 checkCacheability(req);
525
526 if (write)
527 write_hits++;
528 else
529 read_hits++;
530
531 return No_Fault;
532 }
533
534 AlphaISA::PTE &
535 AlphaTlb::index()
536 {
537 AlphaISA::PTE *pte = &table[nlu];
538 nextnlu();
539
540 return *pte;
541 }
542
543 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaItb)
544
545 Param<int> size;
546
547 END_DECLARE_SIM_OBJECT_PARAMS(AlphaItb)
548
549 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaItb)
550
551 INIT_PARAM_DFLT(size, "TLB size", 48)
552
553 END_INIT_SIM_OBJECT_PARAMS(AlphaItb)
554
555
556 CREATE_SIM_OBJECT(AlphaItb)
557 {
558 return new AlphaItb(getInstanceName(), size);
559 }
560
561 REGISTER_SIM_OBJECT("AlphaITB", AlphaItb)
562
563 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb)
564
565 Param<int> size;
566
567 END_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb)
568
569 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDtb)
570
571 INIT_PARAM_DFLT(size, "TLB size", 64)
572
573 END_INIT_SIM_OBJECT_PARAMS(AlphaDtb)
574
575
576 CREATE_SIM_OBJECT(AlphaDtb)
577 {
578 return new AlphaDtb(getInstanceName(), size);
579 }
580
581 REGISTER_SIM_OBJECT("AlphaDTB", AlphaDtb)
582