2 * Copyright (c) 2001-2004 The Regents of The University of Michigan
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.
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.
33 #include "arch/alpha/alpha_memory.hh"
34 #include "base/inifile.hh"
35 #include "base/str.hh"
36 #include "base/trace.hh"
37 #include "cpu/exec_context.hh"
38 #include "sim/builder.hh"
43 ///////////////////////////////////////////////////////////////////////
48 bool uncacheBit39
= false;
49 bool uncacheBit40
= false;
52 #define MODE2MASK(X) (1 << (X))
54 AlphaTLB::AlphaTLB(const string
&name
, int s
)
55 : SimObject(name
), size(s
), nlu(0)
57 table
= new AlphaISA::PTE
[size
];
58 memset(table
, 0, sizeof(AlphaISA::PTE
[size
]));
67 // look up an entry in the TLB
69 AlphaTLB::lookup(Addr vpn
, uint8_t asn
) const
71 // assume not found...
72 AlphaISA::PTE
*retval
= NULL
;
74 PageTable::const_iterator i
= lookupTable
.find(vpn
);
75 if (i
!= lookupTable
.end()) {
76 while (i
->first
== vpn
) {
77 int index
= i
->second
;
78 AlphaISA::PTE
*pte
= &table
[index
];
80 if (vpn
== pte
->tag
&& (pte
->asma
|| pte
->asn
== asn
)) {
89 DPRINTF(TLB
, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn
, (int)asn
,
90 retval
? "hit" : "miss", retval
? retval
->ppn
: 0);
96 AlphaTLB::checkCacheability(MemReqPtr
&req
)
98 // in Alpha, cacheability is controlled by upper-level bits of the
102 * We support having the uncacheable bit in either bit 39 or bit 40.
103 * The Turbolaser platform (and EV5) support having the bit in 39, but
104 * Tsunami (which Linux assumes uses an EV6) generates accesses with
105 * the bit in 40. So we must check for both, but we have debug flags
106 * to catch a weird case where both are used, which shouldn't happen.
111 if (req
->paddr
& PAddrUncachedBit39
) {
113 if (req
->paddr
& PAddrUncachedBit43
) {
115 // IPR memory space not implemented
116 if (PAddrIprSpace(req
->paddr
)) {
117 if (!req
->xc
->misspeculating()) {
118 switch (req
->paddr
) {
119 case ULL(0xFFFFF00188):
124 panic("IPR memory space not implemented! PA=%x\n",
129 // mark request as uncacheable
130 req
->flags
|= UNCACHEABLE
;
133 // Clear bits 42:35 of the physical address (10-2 in Tsunami manual)
134 req
->paddr
&= PAddrUncachedMask
;
141 // insert a new TLB entry
143 AlphaTLB::insert(Addr addr
, AlphaISA::PTE
&pte
)
145 AlphaISA::VAddr vaddr
= addr
;
146 if (table
[nlu
].valid
) {
147 Addr oldvpn
= table
[nlu
].tag
;
148 PageTable::iterator i
= lookupTable
.find(oldvpn
);
150 if (i
== lookupTable
.end())
151 panic("TLB entry not found in lookupTable");
154 while ((index
= i
->second
) != nlu
) {
155 if (table
[index
].tag
!= oldvpn
)
156 panic("TLB entry not found in lookupTable");
161 DPRINTF(TLB
, "remove @%d: %#x -> %#x\n", nlu
, oldvpn
, table
[nlu
].ppn
);
163 lookupTable
.erase(i
);
166 DPRINTF(TLB
, "insert @%d: %#x -> %#x\n", nlu
, vaddr
.vpn(), pte
.ppn
);
169 table
[nlu
].tag
= vaddr
.vpn();
170 table
[nlu
].valid
= true;
172 lookupTable
.insert(make_pair(vaddr
.vpn(), nlu
));
179 memset(table
, 0, sizeof(AlphaISA::PTE
[size
]));
185 AlphaTLB::flushProcesses()
187 PageTable::iterator i
= lookupTable
.begin();
188 PageTable::iterator end
= lookupTable
.end();
190 int index
= i
->second
;
191 AlphaISA::PTE
*pte
= &table
[index
];
195 DPRINTF(TLB
, "flush @%d: %#x -> %#x\n", index
, pte
->tag
, pte
->ppn
);
197 lookupTable
.erase(i
);
205 AlphaTLB::flushAddr(Addr addr
, uint8_t asn
)
207 AlphaISA::VAddr vaddr
= addr
;
209 PageTable::iterator i
= lookupTable
.find(vaddr
.vpn());
210 if (i
== lookupTable
.end())
213 while (i
->first
== vaddr
.vpn()) {
214 int index
= i
->second
;
215 AlphaISA::PTE
*pte
= &table
[index
];
218 if (vaddr
.vpn() == pte
->tag
&& (pte
->asma
|| pte
->asn
== asn
)) {
219 DPRINTF(TLB
, "flushaddr @%d: %#x -> %#x\n", index
, vaddr
.vpn(),
222 // invalidate this entry
225 lookupTable
.erase(i
);
234 AlphaTLB::serialize(ostream
&os
)
236 SERIALIZE_SCALAR(size
);
237 SERIALIZE_SCALAR(nlu
);
239 for (int i
= 0; i
< size
; i
++) {
240 nameOut(os
, csprintf("%s.PTE%d", name(), i
));
241 table
[i
].serialize(os
);
246 AlphaTLB::unserialize(Checkpoint
*cp
, const string
§ion
)
248 UNSERIALIZE_SCALAR(size
);
249 UNSERIALIZE_SCALAR(nlu
);
251 for (int i
= 0; i
< size
; i
++) {
252 table
[i
].unserialize(cp
, csprintf("%s.PTE%d", section
, i
));
253 if (table
[i
].valid
) {
254 lookupTable
.insert(make_pair(table
[i
].tag
, i
));
260 ///////////////////////////////////////////////////////////////////////
264 AlphaITB::AlphaITB(const std::string
&name
, int size
)
265 : AlphaTLB(name
, size
)
273 .name(name() + ".hits")
276 .name(name() + ".misses")
279 .name(name() + ".acv")
282 .name(name() + ".accesses")
283 .desc("ITB accesses");
285 accesses
= hits
+ misses
;
289 AlphaITB::fault(Addr pc
, ExecContext
*xc
) const
291 uint64_t *ipr
= xc
->regs
.ipr
;
293 if (!xc
->misspeculating()) {
294 ipr
[AlphaISA::IPR_ITB_TAG
] = pc
;
295 ipr
[AlphaISA::IPR_IFAULT_VA_FORM
] =
296 ipr
[AlphaISA::IPR_IVPTBR
] | (AlphaISA::VAddr(pc
).vpn() << 3);
302 AlphaITB::translate(MemReqPtr
&req
) const
304 InternalProcReg
*ipr
= req
->xc
->regs
.ipr
;
306 if (AlphaISA::PcPAL(req
->vaddr
)) {
307 // strip off PAL PC marker (lsb is 1)
308 req
->paddr
= (req
->vaddr
& ~3) & PAddrImplMask
;
313 if (req
->flags
& PHYSICAL
) {
314 req
->paddr
= req
->vaddr
;
316 // verify that this is a good virtual address
317 if (!validVirtualAddress(req
->vaddr
)) {
318 fault(req
->vaddr
, req
->xc
);
320 return ITB_Acv_Fault
;
324 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5
325 // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6
327 if ((MCSR_SP(ipr
[AlphaISA::IPR_MCSR
]) & 2) &&
328 VAddrSpaceEV5(req
->vaddr
) == 2) {
330 if (VAddrSpaceEV6(req
->vaddr
) == 0x7e) {
332 // only valid in kernel mode
333 if (ICM_CM(ipr
[AlphaISA::IPR_ICM
]) !=
334 AlphaISA::mode_kernel
) {
335 fault(req
->vaddr
, req
->xc
);
337 return ITB_Acv_Fault
;
340 req
->paddr
= req
->vaddr
& PAddrImplMask
;
343 // sign extend the physical address properly
344 if (req
->paddr
& PAddrUncachedBit40
)
345 req
->paddr
|= ULL(0xf0000000000);
347 req
->paddr
&= ULL(0xffffffffff);
351 // not a physical address: need to look up pte
352 AlphaISA::PTE
*pte
= lookup(AlphaISA::VAddr(req
->vaddr
).vpn(),
353 DTB_ASN_ASN(ipr
[AlphaISA::IPR_DTB_ASN
]));
356 fault(req
->vaddr
, req
->xc
);
358 return ITB_Fault_Fault
;
361 req
->paddr
= (pte
->ppn
<< AlphaISA::PageShift
) +
362 (AlphaISA::VAddr(req
->vaddr
).offset() & ~3);
364 // check permissions for this access
365 if (!(pte
->xre
& (1 << ICM_CM(ipr
[AlphaISA::IPR_ICM
])))) {
366 // instruction access fault
367 fault(req
->vaddr
, req
->xc
);
369 return ITB_Acv_Fault
;
376 // check that the physical address is ok (catch bad physical addresses)
377 if (req
->paddr
& ~PAddrImplMask
)
378 return Machine_Check_Fault
;
380 checkCacheability(req
);
385 ///////////////////////////////////////////////////////////////////////
389 AlphaDTB::AlphaDTB(const std::string
&name
, int size
)
390 : AlphaTLB(name
, size
)
397 .name(name() + ".read_hits")
398 .desc("DTB read hits")
402 .name(name() + ".read_misses")
403 .desc("DTB read misses")
407 .name(name() + ".read_acv")
408 .desc("DTB read access violations")
412 .name(name() + ".read_accesses")
413 .desc("DTB read accesses")
417 .name(name() + ".write_hits")
418 .desc("DTB write hits")
422 .name(name() + ".write_misses")
423 .desc("DTB write misses")
427 .name(name() + ".write_acv")
428 .desc("DTB write access violations")
432 .name(name() + ".write_accesses")
433 .desc("DTB write accesses")
437 .name(name() + ".hits")
442 .name(name() + ".misses")
447 .name(name() + ".acv")
448 .desc("DTB access violations")
452 .name(name() + ".accesses")
453 .desc("DTB accesses")
456 hits
= read_hits
+ write_hits
;
457 misses
= read_misses
+ write_misses
;
458 acv
= read_acv
+ write_acv
;
459 accesses
= read_accesses
+ write_accesses
;
463 AlphaDTB::fault(MemReqPtr
&req
, uint64_t flags
) const
465 ExecContext
*xc
= req
->xc
;
466 AlphaISA::VAddr vaddr
= req
->vaddr
;
467 uint64_t *ipr
= xc
->regs
.ipr
;
469 // Set fault address and flags. Even though we're modeling an
470 // EV5, we use the EV6 technique of not latching fault registers
471 // on VPTE loads (instead of locking the registers until IPR_VA is
472 // read, like the EV5). The EV6 approach is cleaner and seems to
473 // work with EV5 PAL code, but not the other way around.
474 if (!xc
->misspeculating()
475 && !(req
->flags
& VPTE
) && !(req
->flags
& NO_FAULT
)) {
476 // set VA register with faulting address
477 ipr
[AlphaISA::IPR_VA
] = req
->vaddr
;
479 // set MM_STAT register flags
480 ipr
[AlphaISA::IPR_MM_STAT
] =
481 (((Opcode(xc
->getInst()) & 0x3f) << 11)
482 | ((Ra(xc
->getInst()) & 0x1f) << 6)
485 // set VA_FORM register with faulting formatted address
486 ipr
[AlphaISA::IPR_VA_FORM
] =
487 ipr
[AlphaISA::IPR_MVPTBR
] | (vaddr
.vpn() << 3);
492 AlphaDTB::translate(MemReqPtr
&req
, bool write
) const
494 RegFile
*regs
= &req
->xc
->regs
;
496 InternalProcReg
*ipr
= regs
->ipr
;
498 AlphaISA::mode_type mode
=
499 (AlphaISA::mode_type
)DTB_CM_CM(ipr
[AlphaISA::IPR_DTB_CM
]);
503 * Check for alignment faults
505 if (req
->vaddr
& (req
->size
- 1)) {
506 fault(req
, write
? MM_STAT_WR_MASK
: 0);
507 DPRINTF(TLB
, "Alignment Fault on %#x, size = %d", req
->vaddr
,
509 return Alignment_Fault
;
513 mode
= (req
->flags
& ALTMODE
) ?
514 (AlphaISA::mode_type
)ALT_MODE_AM(ipr
[AlphaISA::IPR_ALT_MODE
])
515 : AlphaISA::mode_kernel
;
518 if (req
->flags
& PHYSICAL
) {
519 req
->paddr
= req
->vaddr
;
521 // verify that this is a good virtual address
522 if (!validVirtualAddress(req
->vaddr
)) {
523 fault(req
, (write
? MM_STAT_WR_MASK
: 0) |
524 MM_STAT_BAD_VA_MASK
|
527 if (write
) { write_acv
++; } else { read_acv
++; }
528 return DTB_Fault_Fault
;
531 // Check for "superpage" mapping
533 if ((MCSR_SP(ipr
[AlphaISA::IPR_MCSR
]) & 2) &&
534 VAddrSpaceEV5(req
->vaddr
) == 2) {
536 if (VAddrSpaceEV6(req
->vaddr
) == 0x7e) {
539 // only valid in kernel mode
540 if (DTB_CM_CM(ipr
[AlphaISA::IPR_DTB_CM
]) !=
541 AlphaISA::mode_kernel
) {
542 fault(req
, ((write
? MM_STAT_WR_MASK
: 0) |
544 if (write
) { write_acv
++; } else { read_acv
++; }
545 return DTB_Acv_Fault
;
548 req
->paddr
= req
->vaddr
& PAddrImplMask
;
551 // sign extend the physical address properly
552 if (req
->paddr
& PAddrUncachedBit40
)
553 req
->paddr
|= ULL(0xf0000000000);
555 req
->paddr
&= ULL(0xffffffffff);
564 // not a physical address: need to look up pte
565 AlphaISA::PTE
*pte
= lookup(AlphaISA::VAddr(req
->vaddr
).vpn(),
566 DTB_ASN_ASN(ipr
[AlphaISA::IPR_DTB_ASN
]));
570 fault(req
, (write
? MM_STAT_WR_MASK
: 0) |
571 MM_STAT_DTB_MISS_MASK
);
572 if (write
) { write_misses
++; } else { read_misses
++; }
573 return (req
->flags
& VPTE
) ? Pdtb_Miss_Fault
: Ndtb_Miss_Fault
;
576 req
->paddr
= (pte
->ppn
<< AlphaISA::PageShift
) +
577 AlphaISA::VAddr(req
->vaddr
).offset();
580 if (!(pte
->xwe
& MODE2MASK(mode
))) {
581 // declare the instruction access fault
582 fault(req
, MM_STAT_WR_MASK
|
584 (pte
->fonw
? MM_STAT_FONW_MASK
: 0));
586 return DTB_Fault_Fault
;
589 fault(req
, MM_STAT_WR_MASK
|
592 return DTB_Fault_Fault
;
595 if (!(pte
->xre
& MODE2MASK(mode
))) {
596 fault(req
, MM_STAT_ACV_MASK
|
597 (pte
->fonr
? MM_STAT_FONR_MASK
: 0));
599 return DTB_Acv_Fault
;
602 fault(req
, MM_STAT_FONR_MASK
);
604 return DTB_Fault_Fault
;
615 // check that the physical address is ok (catch bad physical addresses)
616 if (req
->paddr
& ~PAddrImplMask
)
617 return Machine_Check_Fault
;
619 checkCacheability(req
);
625 AlphaTLB::index(bool advance
)
627 AlphaISA::PTE
*pte
= &table
[nlu
];
635 DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", AlphaTLB
)
637 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaITB
)
641 END_DECLARE_SIM_OBJECT_PARAMS(AlphaITB
)
643 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaITB
)
645 INIT_PARAM_DFLT(size
, "TLB size", 48)
647 END_INIT_SIM_OBJECT_PARAMS(AlphaITB
)
650 CREATE_SIM_OBJECT(AlphaITB
)
652 return new AlphaITB(getInstanceName(), size
);
655 REGISTER_SIM_OBJECT("AlphaITB", AlphaITB
)
657 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB
)
661 END_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB
)
663 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDTB
)
665 INIT_PARAM_DFLT(size
, "TLB size", 64)
667 END_INIT_SIM_OBJECT_PARAMS(AlphaDTB
)
670 CREATE_SIM_OBJECT(AlphaDTB
)
672 return new AlphaDTB(getInstanceName(), size
);
675 REGISTER_SIM_OBJECT("AlphaDTB", AlphaDTB
)