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