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 "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"
43 ///////////////////////////////////////////////////////////////////////
47 AlphaTlb::AlphaTlb(const string
&name
, int s
)
48 : SimObject(name
), size(s
), nlu(0)
50 table
= new AlphaISA::PTE
[size
];
51 memset(table
, 0, sizeof(AlphaISA::PTE
[size
]));
60 // look up an entry in the TLB
62 AlphaTlb::lookup(Addr vpn
, uint8_t asn
) const
64 DPRINTF(TLB
, "lookup %#x\n", vpn
);
66 PageTable::const_iterator i
= lookupTable
.find(vpn
);
67 if (i
== lookupTable
.end())
70 while (i
->first
== vpn
) {
71 int index
= i
->second
;
72 AlphaISA::PTE
*pte
= &table
[index
];
74 if (vpn
== pte
->tag
&& (pte
->asma
|| pte
->asn
== asn
))
86 AlphaTlb::checkCacheability(MemReqPtr req
)
88 // in Alpha, cacheability is controlled by upper-level bits of the
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
);
96 // mark request as uncacheable
97 req
->flags
|= UNCACHEABLE
;
103 // insert a new TLB entry
105 AlphaTlb::insert(Addr vaddr
, AlphaISA::PTE
&pte
)
107 if (table
[nlu
].valid
) {
108 Addr oldvpn
= table
[nlu
].tag
;
109 PageTable::iterator i
= lookupTable
.find(oldvpn
);
111 if (i
== lookupTable
.end())
112 panic("TLB entry not found in lookupTable");
115 while ((index
= i
->second
) != nlu
) {
116 if (table
[index
].tag
!= oldvpn
)
117 panic("TLB entry not found in lookupTable");
122 DPRINTF(TLB
, "remove @%d: %#x -> %#x\n", nlu
, oldvpn
, table
[nlu
].ppn
);
124 lookupTable
.erase(i
);
127 Addr vpn
= VA_VPN(vaddr
);
128 DPRINTF(TLB
, "insert @%d: %#x -> %#x\n", nlu
, vpn
, pte
.ppn
);
131 table
[nlu
].tag
= vpn
;
132 table
[nlu
].valid
= true;
134 lookupTable
.insert(make_pair(vpn
, nlu
));
141 memset(table
, 0, sizeof(AlphaISA::PTE
[size
]));
147 AlphaTlb::flushProcesses()
149 PageTable::iterator i
= lookupTable
.begin();
150 PageTable::iterator end
= lookupTable
.end();
152 int index
= i
->second
;
153 AlphaISA::PTE
*pte
= &table
[index
];
157 DPRINTF(TLB
, "flush @%d: %#x -> %#x\n", index
, pte
->tag
, pte
->ppn
);
159 lookupTable
.erase(i
);
167 AlphaTlb::flushAddr(Addr vaddr
, uint8_t asn
)
169 Addr vpn
= VA_VPN(vaddr
);
171 PageTable::iterator i
= lookupTable
.find(vpn
);
172 if (i
== lookupTable
.end())
175 while (i
->first
== vpn
) {
176 int index
= i
->second
;
177 AlphaISA::PTE
*pte
= &table
[index
];
180 if (vpn
== pte
->tag
&& (pte
->asma
|| pte
->asn
== asn
)) {
181 DPRINTF(TLB
, "flushaddr @%d: %#x -> %#x\n", index
, vpn
, pte
->ppn
);
183 // invalidate this entry
186 lookupTable
.erase(i
);
195 AlphaTlb::serialize(ostream
&os
)
197 SERIALIZE_SCALAR(size
);
198 SERIALIZE_SCALAR(nlu
);
200 // should just add serialize/unserialize methods to AlphaPTE
203 for (int i
= 0; i
< size
; i
++) {
205 ccprintf(buf
, "pte%02d.valid", i
);
206 paramOut(buf
.str(), table
[i
].valid
);
209 ccprintf(buf
, "pte%02d.tag", i
);
210 paramOut(buf
.str(), table
[i
].tag
);
213 ccprintf(buf
, "pte%02d.ppn", i
);
214 paramOut(buf
.str(), table
[i
].ppn
);
217 ccprintf(buf
, "pte%02d.xre", i
);
218 paramOut(buf
.str(), table
[i
].xre
);
221 ccprintf(buf
, "pte%02d.xwe", i
);
222 paramOut(buf
.str(), table
[i
].xwe
);
225 ccprintf(buf
, "pte%02d.fonr", i
);
226 paramOut(buf
.str(), table
[i
].fonr
);
229 ccprintf(buf
, "pte%02d.fonw", i
);
230 paramOut(buf
.str(), table
[i
].fonw
);
233 ccprintf(buf
, "pte%02d.asma", i
);
234 paramOut(buf
.str(), table
[i
].asma
);
237 ccprintf(buf
, "pte%02d.asn", i
);
238 paramOut(buf
.str(), table
[i
].asn
);
244 AlphaTlb::unserialize(const IniFile
*db
, const string
§ion
)
246 UNSERIALIZE_SCALAR(size
);
247 UNSERIALIZE_SCALAR(nlu
);
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
);
302 ///////////////////////////////////////////////////////////////////////
306 AlphaItb::AlphaItb(const std::string
&name
, int size
)
307 : AlphaTlb(name
, size
)
315 .name(name() + ".hits")
318 .name(name() + ".misses")
321 .name(name() + ".acv")
324 .name(name() + ".accesses")
325 .desc("ITB accesses");
327 accesses
= hits
+ misses
;
331 AlphaItb::fault(Addr pc
, ExecContext
*xc
) const
333 uint64_t *ipr
= xc
->regs
.ipr
;
335 if (!xc
->misspeculating()) {
336 ipr
[AlphaISA::IPR_ITB_TAG
] = pc
;
337 ipr
[AlphaISA::IPR_IFAULT_VA_FORM
] =
338 ipr
[AlphaISA::IPR_IVPTBR
] | (VA_VPN(pc
) << 3);
344 AlphaItb::translate(MemReqPtr req
) const
346 InternalProcReg
*ipr
= req
->xc
->regs
.ipr
;
348 if (PC_PAL(req
->vaddr
)) {
349 // strip off PAL PC marker (lsb is 1)
350 req
->paddr
= (req
->vaddr
& ~3) & PA_IMPL_MASK
;
355 // verify that this is a good virtual address
356 if (!validVirtualAddress(req
->vaddr
)) {
357 fault(req
->vaddr
, req
->xc
);
359 return Itb_Acv_Fault
;
362 // Check for "superpage" mapping: when SP<1> is set, and
363 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
364 if ((MCSR_SP(ipr
[AlphaISA::IPR_MCSR
]) & 2) &&
365 VA_SPACE(req
->vaddr
) == 2) {
366 // only valid in kernel mode
367 if (ICM_CM(ipr
[AlphaISA::IPR_ICM
]) != AlphaISA::mode_kernel
) {
368 fault(req
->vaddr
, req
->xc
);
370 return Itb_Acv_Fault
;
373 req
->flags
|= PHYSICAL
;
376 if (req
->flags
& PHYSICAL
) {
377 req
->paddr
= req
->vaddr
& PA_IMPL_MASK
;
379 // not a physical address: need to look up pte
381 AlphaISA::PTE
*pte
= lookup(VA_VPN(req
->vaddr
),
382 DTB_ASN_ASN(ipr
[AlphaISA::IPR_DTB_ASN
]));
385 fault(req
->vaddr
, req
->xc
);
387 return Itb_Fault_Fault
;
390 req
->paddr
= PA_PFN2PA(pte
->ppn
) + VA_POFS(req
->vaddr
& ~3);
392 // check permissions for this access
393 if (!(pte
->xre
& (1 << ICM_CM(ipr
[AlphaISA::IPR_ICM
])))) {
394 // instruction access fault
395 fault(req
->vaddr
, req
->xc
);
397 return Itb_Acv_Fault
;
401 checkCacheability(req
);
407 ///////////////////////////////////////////////////////////////////////
411 AlphaDtb::AlphaDtb(const std::string
&name
, int size
)
412 : AlphaTlb(name
, size
)
419 .name(name() + ".read_hits")
420 .desc("DTB read hits")
424 .name(name() + ".read_misses")
425 .desc("DTB read misses")
429 .name(name() + ".read_acv")
430 .desc("DTB read access violations")
434 .name(name() + ".read_accesses")
435 .desc("DTB read accesses")
439 .name(name() + ".write_hits")
440 .desc("DTB write hits")
444 .name(name() + ".write_misses")
445 .desc("DTB write misses")
449 .name(name() + ".write_acv")
450 .desc("DTB write access violations")
454 .name(name() + ".write_accesses")
455 .desc("DTB write accesses")
459 .name(name() + ".hits")
464 .name(name() + ".misses")
469 .name(name() + ".acv")
470 .desc("DTB access violations")
474 .name(name() + ".accesses")
475 .desc("DTB accesses")
478 hits
= read_hits
+ write_hits
;
479 misses
= read_misses
+ write_misses
;
480 acv
= read_acv
+ write_acv
;
481 accesses
= read_accesses
+ write_accesses
;
485 AlphaDtb::fault(Addr vaddr
, uint64_t flags
, ExecContext
*xc
) const
487 uint64_t *ipr
= xc
->regs
.ipr
;
489 // set fault address and flags
490 if (!xc
->misspeculating() && !xc
->regs
.intrlock
) {
491 // set VA register with faulting address
492 ipr
[AlphaISA::IPR_VA
] = vaddr
;
494 // set MM_STAT register flags
495 ipr
[AlphaISA::IPR_MM_STAT
] = (((xc
->regs
.opcode
& 0x3f) << 11)
496 | ((xc
->regs
.ra
& 0x1f) << 6)
499 // set VA_FORM register with faulting formatted address
500 ipr
[AlphaISA::IPR_VA_FORM
] =
501 ipr
[AlphaISA::IPR_MVPTBR
] | (VA_VPN(vaddr
) << 3);
503 // lock these registers until the VA register is read
504 xc
->regs
.intrlock
= true;
509 AlphaDtb::translate(MemReqPtr req
, bool write
) const
511 RegFile
*regs
= &req
->xc
->regs
;
513 InternalProcReg
*ipr
= regs
->ipr
;
520 AlphaISA::md_mode_type mode
=
521 (AlphaISA::md_mode_type
)DTB_CM_CM(ipr
[AlphaISA::IPR_DTB_CM
]);
524 mode
= (req
->flags
& ALTMODE
) ? (AlphaISA::md_mode_type
)
525 (ALT_MODE_AM(ipr
[AlphaISA::IPR_ALT_MODE
]))
526 : AlphaISA::mode_kernel
;
529 // verify that this is a good virtual address
530 if (!validVirtualAddress(req
->vaddr
)) {
532 ((write
? MM_STAT_WR_MASK
: 0) | MM_STAT_BAD_VA_MASK
|
536 if (write
) { write_acv
++; } else { read_acv
++; }
537 return Dtb_Fault_Fault
;
540 // Check for "superpage" mapping: when SP<1> is set, and
541 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
542 if ((MCSR_SP(ipr
[AlphaISA::IPR_MCSR
]) & 2) && VA_SPACE(req
->vaddr
) == 2) {
543 // only valid in kernel mode
544 if (DTB_CM_CM(ipr
[AlphaISA::IPR_DTB_CM
]) != AlphaISA::mode_kernel
) {
546 ((write
? MM_STAT_WR_MASK
: 0) | MM_STAT_ACV_MASK
),
548 if (write
) { write_acv
++; } else { read_acv
++; }
549 return Dtb_Acv_Fault
;
552 req
->flags
|= PHYSICAL
;
555 if (req
->flags
& PHYSICAL
) {
556 req
->paddr
= req
->vaddr
& PA_IMPL_MASK
;
558 // not a physical address: need to look up pte
560 AlphaISA::PTE
*pte
= lookup(VA_VPN(req
->vaddr
),
561 DTB_ASN_ASN(ipr
[AlphaISA::IPR_DTB_ASN
]));
566 ((write
? MM_STAT_WR_MASK
: 0) | MM_STAT_DTB_MISS_MASK
),
568 if (write
) { write_misses
++; } else { read_misses
++; }
569 return (req
->flags
& VPTE
) ? Pdtb_Miss_Fault
: Ndtb_Miss_Fault
;
572 req
->paddr
= PA_PFN2PA(pte
->ppn
) | VA_POFS(req
->vaddr
);
575 if (!(pte
->xwe
& MODE2MASK(mode
))) {
576 // declare the instruction access fault
577 fault(req
->vaddr
, MM_STAT_WR_MASK
| MM_STAT_ACV_MASK
|
578 (pte
->fonw
? MM_STAT_FONW_MASK
: 0),
581 return Dtb_Fault_Fault
;
584 fault(req
->vaddr
, MM_STAT_WR_MASK
| MM_STAT_FONW_MASK
,
587 return Dtb_Fault_Fault
;
590 if (!(pte
->xre
& MODE2MASK(mode
))) {
592 MM_STAT_ACV_MASK
| (pte
->fonr
? MM_STAT_FONR_MASK
: 0),
595 return Dtb_Acv_Fault
;
598 fault(req
->vaddr
, MM_STAT_FONR_MASK
, req
->xc
);
600 return Dtb_Fault_Fault
;
605 checkCacheability(req
);
618 AlphaISA::PTE
*pte
= &table
[nlu
];
624 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaItb
)
628 END_DECLARE_SIM_OBJECT_PARAMS(AlphaItb
)
630 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaItb
)
632 INIT_PARAM_DFLT(size
, "TLB size", 48)
634 END_INIT_SIM_OBJECT_PARAMS(AlphaItb
)
637 CREATE_SIM_OBJECT(AlphaItb
)
639 return new AlphaItb(getInstanceName(), size
);
642 REGISTER_SIM_OBJECT("AlphaITB", AlphaItb
)
644 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb
)
648 END_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb
)
650 BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDtb
)
652 INIT_PARAM_DFLT(size
, "TLB size", 64)
654 END_INIT_SIM_OBJECT_PARAMS(AlphaDtb
)
657 CREATE_SIM_OBJECT(AlphaDtb
)
659 return new AlphaDtb(getInstanceName(), size
);
662 REGISTER_SIM_OBJECT("AlphaDTB", AlphaDtb
)