2 * Copyright (c) 2003 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 "alpha_memory.hh"
35 #include "exec_context.hh"
42 ///////////////////////////////////////////////////////////////////////
46 AlphaTlb::AlphaTlb(const string
&name
, int s
)
47 : SimObject(name
), size(s
), nlu(0)
49 table
= new AlphaISA::PTE
[size
];
50 memset(table
, 0, sizeof(AlphaISA::PTE
[size
]));
59 // look up an entry in the TLB
61 AlphaTlb::lookup(Addr vpn
, uint8_t asn
) const
63 DPRINTF(TLB
, "lookup %#x\n", vpn
);
65 PageTable::const_iterator i
= lookupTable
.find(vpn
);
66 if (i
== lookupTable
.end())
69 while (i
->first
== vpn
) {
70 int index
= i
->second
;
71 AlphaISA::PTE
*pte
= &table
[index
];
73 if (vpn
== pte
->tag
&& (pte
->asma
|| pte
->asn
== asn
))
85 AlphaTlb::checkCacheability(MemReqPtr req
)
87 // in Alpha, cacheability is controlled by upper-level bits of the
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
);
95 // mark request as uncacheable
96 req
->flags
|= UNCACHEABLE
;
102 // insert a new TLB entry
104 AlphaTlb::insert(Addr vaddr
, AlphaISA::PTE
&pte
)
106 if (table
[nlu
].valid
) {
107 Addr oldvpn
= table
[nlu
].tag
;
108 PageTable::iterator i
= lookupTable
.find(oldvpn
);
110 if (i
== lookupTable
.end())
111 panic("TLB entry not found in lookupTable");
114 while ((index
= i
->second
) != nlu
) {
115 if (table
[index
].tag
!= oldvpn
)
116 panic("TLB entry not found in lookupTable");
121 DPRINTF(TLB
, "remove @%d: %#x -> %#x\n", nlu
, oldvpn
, table
[nlu
].ppn
);
123 lookupTable
.erase(i
);
126 Addr vpn
= VA_VPN(vaddr
);
127 DPRINTF(TLB
, "insert @%d: %#x -> %#x\n", nlu
, vpn
, pte
.ppn
);
130 table
[nlu
].tag
= vpn
;
131 table
[nlu
].valid
= true;
133 lookupTable
.insert(make_pair(vpn
, nlu
));
140 memset(table
, 0, sizeof(AlphaISA::PTE
[size
]));
146 AlphaTlb::flushProcesses()
148 PageTable::iterator i
= lookupTable
.begin();
149 PageTable::iterator end
= lookupTable
.end();
151 int index
= i
->second
;
152 AlphaISA::PTE
*pte
= &table
[index
];
156 DPRINTF(TLB
, "flush @%d: %#x -> %#x\n", index
, pte
->tag
, pte
->ppn
);
158 lookupTable
.erase(i
);
166 AlphaTlb::flushAddr(Addr vaddr
, uint8_t asn
)
168 Addr vpn
= VA_VPN(vaddr
);
170 PageTable::iterator i
= lookupTable
.find(vpn
);
171 if (i
== lookupTable
.end())
174 while (i
->first
== vpn
) {
175 int index
= i
->second
;
176 AlphaISA::PTE
*pte
= &table
[index
];
179 if (vpn
== pte
->tag
&& (pte
->asma
|| pte
->asn
== asn
)) {
180 DPRINTF(TLB
, "flushaddr @%d: %#x -> %#x\n", index
, vpn
, pte
->ppn
);
182 // invalidate this entry
185 lookupTable
.erase(i
);
194 AlphaTlb::serialize()
198 paramOut("size", size
);
199 paramOut("nlu", nlu
);
202 for (int i
= 0; i
< size
; i
++) {
204 ccprintf(buf
, "pte%02d.valid", i
);
205 paramOut(buf
.str(), table
[i
].valid
);
208 ccprintf(buf
, "pte%02d.tag", i
);
209 paramOut(buf
.str(), table
[i
].tag
);
212 ccprintf(buf
, "pte%02d.ppn", i
);
213 paramOut(buf
.str(), table
[i
].ppn
);
216 ccprintf(buf
, "pte%02d.xre", i
);
217 paramOut(buf
.str(), table
[i
].xre
);
220 ccprintf(buf
, "pte%02d.xwe", i
);
221 paramOut(buf
.str(), table
[i
].xwe
);
224 ccprintf(buf
, "pte%02d.fonr", i
);
225 paramOut(buf
.str(), table
[i
].fonr
);
228 ccprintf(buf
, "pte%02d.fonw", i
);
229 paramOut(buf
.str(), table
[i
].fonw
);
232 ccprintf(buf
, "pte%02d.asma", i
);
233 paramOut(buf
.str(), table
[i
].asma
);
236 ccprintf(buf
, "pte%02d.asn", i
);
237 paramOut(buf
.str(), table
[i
].asn
);
242 AlphaTlb::unserialize(IniFile
&db
, const string
&category
, ConfigNode
*node
)
247 db
.findDefault(category
,"size",data
);
248 to_number(data
,size
);
249 db
.findDefault(category
,"nlu",data
);
252 for (int i
= 0; i
< size
; i
++) {
254 ccprintf(buf
, "pte%02d.valid", i
);
255 db
.findDefault(category
, buf
.str(), data
);
256 to_number(data
, table
[i
].valid
);
259 ccprintf(buf
, "pte%02d.tag", i
);
260 db
.findDefault(category
, buf
.str(), data
);
261 to_number(data
, table
[i
].tag
);
264 ccprintf(buf
, "pte%02d.ppn", i
);
265 db
.findDefault(category
, buf
.str(), data
);
266 to_number(data
, table
[i
].ppn
);
269 ccprintf(buf
, "pte%02d.xre", i
);
270 db
.findDefault(category
, buf
.str(), data
);
271 to_number(data
, table
[i
].xre
);
274 ccprintf(buf
, "pte%02d.xwe", i
);
275 db
.findDefault(category
, buf
.str(), data
);
276 to_number(data
, table
[i
].xwe
);
279 ccprintf(buf
, "pte%02d.fonr", i
);
280 db
.findDefault(category
, buf
.str(), data
);
281 to_number(data
, table
[i
].fonr
);
284 ccprintf(buf
, "pte%02d.fonw", i
);
285 db
.findDefault(category
, buf
.str(), data
);
286 to_number(data
, table
[i
].fonw
);
289 ccprintf(buf
, "pte%02d.asma", i
);
290 db
.findDefault(category
, buf
.str(), data
);
291 to_number(data
, table
[i
].asma
);
294 ccprintf(buf
, "pte%02d.asn", i
);
295 db
.findDefault(category
, buf
.str(), data
);
296 to_number(data
, table
[i
].asn
);
301 ///////////////////////////////////////////////////////////////////////
305 AlphaItb::AlphaItb(const std::string
&name
, int size
)
306 : AlphaTlb(name
, size
)
314 .name(name() + ".hits")
317 .name(name() + ".misses")
320 .name(name() + ".acv")
323 .name(name() + ".accesses")
324 .desc("ITB accesses");
326 accesses
= hits
+ misses
;
330 AlphaItb::fault(Addr pc
, ExecContext
*xc
) const
332 uint64_t *ipr
= xc
->regs
.ipr
;
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);
343 AlphaItb::translate(MemReqPtr req
) const
345 InternalProcReg
*ipr
= req
->xc
->regs
.ipr
;
347 if (PC_PAL(req
->vaddr
)) {
348 // strip off PAL PC marker (lsb is 1)
349 req
->paddr
= (req
->vaddr
& ~3) & PA_IMPL_MASK
;
354 // verify that this is a good virtual address
355 if (!validVirtualAddress(req
->vaddr
)) {
356 fault(req
->vaddr
, req
->xc
);
358 return Itb_Acv_Fault
;
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
);
369 return Itb_Acv_Fault
;
372 req
->flags
|= PHYSICAL
;
375 if (req
->flags
& PHYSICAL
) {
376 req
->paddr
= req
->vaddr
& PA_IMPL_MASK
;
378 // not a physical address: need to look up pte
380 AlphaISA::PTE
*pte
= lookup(VA_VPN(req
->vaddr
),
381 DTB_ASN_ASN(ipr
[AlphaISA::IPR_DTB_ASN
]));
384 fault(req
->vaddr
, req
->xc
);
386 return Itb_Fault_Fault
;
389 req
->paddr
= PA_PFN2PA(pte
->ppn
) + VA_POFS(req
->vaddr
& ~3);
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
);
396 return Itb_Acv_Fault
;
400 checkCacheability(req
);
406 ///////////////////////////////////////////////////////////////////////
410 AlphaDtb::AlphaDtb(const std::string
&name
, int size
)
411 : AlphaTlb(name
, size
)
418 .name(name() + ".read_hits")
419 .desc("DTB read hits")
423 .name(name() + ".read_misses")
424 .desc("DTB read misses")
428 .name(name() + ".read_acv")
429 .desc("DTB read access violations")
433 .name(name() + ".read_accesses")
434 .desc("DTB read accesses")
438 .name(name() + ".write_hits")
439 .desc("DTB write hits")
443 .name(name() + ".write_misses")
444 .desc("DTB write misses")
448 .name(name() + ".write_acv")
449 .desc("DTB write access violations")
453 .name(name() + ".write_accesses")
454 .desc("DTB write accesses")
458 .name(name() + ".hits")
463 .name(name() + ".misses")
468 .name(name() + ".acv")
469 .desc("DTB access violations")
473 .name(name() + ".accesses")
474 .desc("DTB accesses")
477 hits
= read_hits
+ write_hits
;
478 misses
= read_misses
+ write_misses
;
479 acv
= read_acv
+ write_acv
;
480 accesses
= read_accesses
+ write_accesses
;
484 AlphaDtb::fault(Addr vaddr
, uint64_t flags
, ExecContext
*xc
) const
486 uint64_t *ipr
= xc
->regs
.ipr
;
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
;
493 // set MM_STAT register flags
494 ipr
[AlphaISA::IPR_MM_STAT
] = (((xc
->regs
.opcode
& 0x3f) << 11)
495 | ((xc
->regs
.ra
& 0x1f) << 6)
498 // set VA_FORM register with faulting formatted address
499 ipr
[AlphaISA::IPR_VA_FORM
] =
500 ipr
[AlphaISA::IPR_MVPTBR
] | (VA_VPN(vaddr
) << 3);
502 // lock these registers until the VA register is read
503 xc
->regs
.intrlock
= true;
508 AlphaDtb::translate(MemReqPtr req
, bool write
) const
510 RegFile
*regs
= &req
->xc
->regs
;
512 InternalProcReg
*ipr
= regs
->ipr
;
519 AlphaISA::md_mode_type mode
=
520 (AlphaISA::md_mode_type
)DTB_CM_CM(ipr
[AlphaISA::IPR_DTB_CM
]);
523 mode
= (req
->flags
& ALTMODE
) ? (AlphaISA::md_mode_type
)
524 (ALT_MODE_AM(ipr
[AlphaISA::IPR_ALT_MODE
]))
525 : AlphaISA::mode_kernel
;
528 // verify that this is a good virtual address
529 if (!validVirtualAddress(req
->vaddr
)) {
531 ((write
? MM_STAT_WR_MASK
: 0) | MM_STAT_BAD_VA_MASK
|
535 if (write
) { write_acv
++; } else { read_acv
++; }
536 return Dtb_Fault_Fault
;
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
) {
545 ((write
? MM_STAT_WR_MASK
: 0) | MM_STAT_ACV_MASK
),
547 if (write
) { write_acv
++; } else { read_acv
++; }
548 return Dtb_Acv_Fault
;
551 req
->flags
|= PHYSICAL
;
554 if (req
->flags
& PHYSICAL
) {
555 req
->paddr
= req
->vaddr
& PA_IMPL_MASK
;
557 // not a physical address: need to look up pte
559 AlphaISA::PTE
*pte
= lookup(VA_VPN(req
->vaddr
),
560 DTB_ASN_ASN(ipr
[AlphaISA::IPR_DTB_ASN
]));
565 ((write
? MM_STAT_WR_MASK
: 0) | MM_STAT_DTB_MISS_MASK
),
567 if (write
) { write_misses
++; } else { read_misses
++; }
568 return (req
->flags
& VPTE
) ? Pdtb_Miss_Fault
: Ndtb_Miss_Fault
;
571 req
->paddr
= PA_PFN2PA(pte
->ppn
) | VA_POFS(req
->vaddr
);
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),
580 return Dtb_Fault_Fault
;
583 fault(req
->vaddr
, MM_STAT_WR_MASK
| MM_STAT_FONW_MASK
,
586 return Dtb_Fault_Fault
;
589 if (!(pte
->xre
& MODE2MASK(mode
))) {
591 MM_STAT_ACV_MASK
| (pte
->fonr
? MM_STAT_FONR_MASK
: 0),
594 return Dtb_Acv_Fault
;
597 fault(req
->vaddr
, MM_STAT_FONR_MASK
, req
->xc
);
599 return Dtb_Fault_Fault
;
604 checkCacheability(req
);
617 AlphaISA::PTE
*pte
= &table
[nlu
];
623 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaItb
)
627 END_DECLARE_SIM_OBJECT_PARAMS(AlphaItb
)
629 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaItb
)
631 INIT_PARAM_DFLT(size
, "TLB size", 48)
633 END_INIT_SIM_OBJECT_PARAMS(AlphaItb
)
636 CREATE_SIM_OBJECT(AlphaItb
)
638 return new AlphaItb(getInstanceName(), size
);
641 REGISTER_SIM_OBJECT("AlphaITB", AlphaItb
)
643 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb
)
647 END_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb
)
649 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDtb
)
651 INIT_PARAM_DFLT(size
, "TLB size", 64)
653 END_INIT_SIM_OBJECT_PARAMS(AlphaDtb
)
656 CREATE_SIM_OBJECT(AlphaDtb
)
658 return new AlphaDtb(getInstanceName(), size
);
661 REGISTER_SIM_OBJECT("AlphaDTB", AlphaDtb
)